Сохранение порядка перечислений в Java

В 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 и т. д.

12
задан sebkur 2 January 2018 в 12:44
поделиться