Получение значения из EnumSet в Java

Если вы используете EnumSetдля хранения обычных двоичных значений (1,2,4 и т. Д.), То при наличии менее 64 элементов я считаю, что это сохраняется в виде битового вектора и эффективно представляется в виде длинного. Есть ли простой способ получить значение этого длинного. Я хочу быстрый и простой способ хранения содержимого набора в файл или базу данных.

Если бы я делал это по-старому, я бы просто использовал long и делал немного самостоятельно, несмотря на все проблемы безопасности типов и т. Д.

12.12.2008 17:42:41
7 ОТВЕТОВ
РЕШЕНИЕ

Насколько я знаю, это не разоблачено. Вы могли бы переписать его самостоятельно - взгляните на код EnumSet, чтобы получить представление о коде - но жаль, что нет более приятного способа получить его :(

6
12.12.2008 17:58:06
Для получения значения можно использовать отраженную темную магию, хотя это не будет ни «быстрым», ни «простым».
Greg Case 12.12.2008 18:03:36
EnumSet на самом деле абстрактный, так что было бы еще хуже.
Michael Myers♦ 12.12.2008 18:12:58

EnumSetреализует Serializable, так что вы можете просто написать это с ObjectOutputStream.

1
12.12.2008 17:53:47

Я не думаю, что это можно сделать общим способом. Преобразовать в длинную довольно легко:

public static <T extends Enum<T>> long enumSetToLong(EnumSet<T> set)
{
    long r = 0;
    for(T value : set)
    {
        r |= 1L << value.ordinal();
    }
    return r;
}

Я не знаю, как вы можете конвертировать длинный назад в EnumSet вообще. Я не знаю способа (если не считать отражения) получить массив значений перечисления для поиска. Вы должны сделать это на основе перечисления.

Я думаю, что сериализация - это путь. Простая сериализация как long будет более восприимчива к ошибкам управления версиями или ошибкам, вызванным перестановкой констант в перечислении.

5
12.12.2008 18:38:31
Вы действительно должны проверить, что порядковые номера меньше 64. long (+ Class) для EnumSet должен быть выполнимым - вы можете получить все значения из enum.
Tom Hawtin - tackline 14.12.2008 16:09:07
++, но на самом деле, вы не должны использовать ординалы. Настройте внутреннюю систему индексации
k_g 14.02.2015 07:12:26

(Типичная - не обязательная) реализация EnumSet использует порядковые номера значений enum. Вы не должны предполагать, что порядковые номера всегда будут такими же. Таким образом, если вы хотите эффективно хранить наборы перечислений с использованием порядковых номеров, вам следует также сохранить карту от имени перечисления до порядкового номера (вероятно, сохраненную как последовательность имен перечисления).

Сам EnumSet, похоже, не имеет отличную сериализованную форму. Это просто выбрасывает перечисления. Тело которого будет транскрибировано в серию целочисленных ссылок на объекты, а не в набор битов.

0
14.12.2008 16:09:46

BitSetМожет быть полезно в этой ситуации, поскольку обеспечивает преобразование в / из массива байтов. Вам все еще может потребоваться объявить enumс явными значениями (1,2,3 ..) для BitSetIndeces. В отличие от long, который всегда 64-битный, BitSetкажется, не позволяет ограничить его длину (например, до 64 бит).

0
16.12.2013 12:41:49

Как отметил Джон Скит, эта информация не раскрывается. Но Дейв Рэй показал, как легко это вычислить. Я сделал библиотеку, которая делает такие преобразования намного проще. Он также проверяет, что на самом деле не более 64 элементов, если вы используете «long». Мне пришлось создать новый тип данных, но он может быть использован как BitSet или EnumSet. Обратите внимание, что для этого требуется Java 8 или новее, поскольку для этого используются интерфейсы с реализациями по умолчанию.

Вот ссылка: http://claude-martin.ch/enumbitset/

Пример:

  static enum MyEnum implements EnumBitSetHelper<MyEnum> { A, B, C }
  public static void main(final String[] args) {
    final EnumBitSet<MyEnum> set = EnumBitSet.of(MyEnum.A, MyEnum.C);
    long bitmask = set.toLong(); // = 3
  }
2
28.04.2014 09:27:35

если добавить параметр с классом перечисления, это возможно. пример, который преобразует enumset в байт:

public static <T extends Enum<T>, U extends Enum<?>> byte toByte(EnumSet<T> set, Class<U> type) {
  byte b = 0;

  if(type.getEnumConstants().length > 8) {
    throw new RuntimeException("enum set doesn't fit in one byte");
  }

  for(Enum<?> e: type.getEnumConstants()) {
    if(set.contains(e)) {
      b |= 1 << e.ordinal();
    }
  }

  return b;
}

public static <E extends Enum<E>> EnumSet<E> toSet(byte b, Class<E> type) {
  E[] enums = type.getEnumConstants();
  EnumSet<E> enumSet = EnumSet.noneOf(type);

  for(int bit = 0; bit < 8; bit++) {
    if((b & 1 << bit) > 0) {
      enumSet.add(enums[bit]);
    }
  }

  return enumSet;
}
1
12.08.2014 16:46:46