В java EnumSet хранит элементы, которые он содержит в битовой маске/битовом векторе, используя long
(RegularEnumSet
) или long[]
(JumboEnumSet
). Теперь я столкнулся с прецедентом, в котором у меня много тысяч объектов домена (пусть их называют Node
), каждый из которых будет отображать все элементы перечисления (пусть вызов Flag
) в порядке, который будет зависеть от каждого объекта.
В настоящее время я сохраняю заказ как Guava ImmutableSet
, потому что это гарантирует сохранение порядка вставки. Тем не менее, я использовал методы, описанные на этой странице, чтобы сравнить использование памяти в EnumSet<Flag>
, a ImmutableSet<Flag>
и a Flag[]
. Вот результаты, когда a) Flag имеет 64 элемента перечисления и b) все три варианта содержат все 64 элемента:
EnumSet: 32 байт
ImmutableSet: 832 байт
Массив: 272 байта
Итак, мой вопрос: есть ли уловкий способ упаковать порядок перечисления в числовое значение, чтобы получить объем памяти меньше, чем размер массива? Если это имеет значение: в моем случае я бы предположил, что порядок всегда содержит все элементы Enum.
Чтобы уточнить: мое перечисление намного меньше этого, и на данный момент у меня нет проблем с памятью, и вряд ли эта ситуация когда-нибудь вызовет проблемы с памятью. Это просто, что эта неэффективность меня беспокоит даже на этом микроскопическом уровне.
Update:
После предложений из различных ответов и комментариев я придумал эту структуру данных, которая использует массив байтов. Предостережение: он не реализует интерфейс Set (не проверяет уникальные значения), и он не будет масштабироваться до больших перечислений, кроме того, что может содержать байт. Кроме того, сложность довольно ужасная, так как Enum.values () нужно повторять повторно (см. Здесь для обсуждение этой проблемы), но здесь говорится:
public class EnumOrdering<E extends Enum<E>> implements Iterable<E> {
private final Class<E> type;
private final byte[] order;
public EnumOrdering(final Class<E> type, final Collection<E> 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<E> iterator() {
return new AbstractIterator<E>() {
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 и т.д.