В java EnumSet хранит содержащиеся в нем элементы в битовой маске/битовом векторе, используя long
( RegularEnumSet
) или long[]
( JumboEnumSet
). Теперь я столкнулся с вариантом использования, когда у меня есть много тысяч объектов домена (назовем их Node
), каждый из которых будет отображать все элементы перечисления (назовем это Flag
) в порядке, который будет варьироваться в зависимости от объекта.
В настоящее время я храню Order как GuavaImmutableSet
, потому что это гарантирует сохранение порядка вставки. Однако я использовал методы, описанные на этой странице, чтобы сравнить использование памяти в EnumSet
, ImmutableSet
и Флаг[]
. Вот результаты, когда а) флаг имеет 64 элемента перечисления и б) все три варианта содержат все 64 элемента:
EnumSet: 32 байта
ImmutableSet: 832 байта
Массив: 272 байта
Итак, мой вопрос: есть ли умный способ упаковать порядок перечисления в числовое значение, чтобы получить меньший объем памяти, чем у массива? Если это имеет значение: в моем случае использования я бы предположил, что порядок всегда содержит все элементы Enum.
Для уточнения: мое перечисление намного меньше, чем это, и у меня нет проблем с памятью на данный момент, и маловероятно, что эта ситуация когда-либо вызовет у меня проблемы с памятью.Просто эта неэффективность меня раздражает даже на таком микроскопическом уровне.
Обновление:
После предложений из различных ответов и комментариев я придумал эту структуру данных, которая использует массив байтов. Предупреждение: он не реализует интерфейс Set (не проверяет уникальные значения) и не масштабируется до больших перечислений, превышающих то, что может содержать байт. Кроме того, сложность довольно ужасна, потому что Enum.values() приходится многократно запрашивать (обсуждение этой проблемы см. здесь), но вот:
public class EnumOrdering> implements Iterable {
private final Class type;
private final byte[] order;
public EnumOrdering(final Class type, final Collection order) {
this.type = type;
this.order = new byte[order.size()];
int offset = 0;
for (final E item : order) {
this.order[offset++] = (byte) item.ordinal();
}
}
@Override
public Iterator iterator() {
return new AbstractIterator() {
private int offset = -1;
private final E[] enumConstants = type.getEnumConstants();
@Override
protected E computeNext() {
if (offset < order.length - 1) {
return enumConstants[order[++offset]];
}
return endOfData();
}
};
}
}
Объем памяти:
EnumOrdering:104
На данный момент это довольно хороший результат, спасибо bestsss и JB Nizet!
Обновление: я изменил код так, чтобы он реализовывал только Iterable, потому что все остальное потребовало бы разумной реализации для equals / hashCode / contains и т. д.