Таким образом в C++/C# можно создать перечисления флагов для содержания нескольких значений, и хранение единственного значимого целого числа в базе данных, конечно, тривиально.
В Java у Вас есть EnumSets, которые, кажется, вполне хороший способ раздать перечисления в памяти, но как Вы производите объединенный EnumSet к целому числу для устройства хранения данных? Там другой путь состоит в том, чтобы приблизиться к этому?
// From Adamski's answer
public static <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= 1 << val.ordinal();
}
return ret;
}
@SuppressWarnings("unchecked")
private static <E extends Enum<E>> EnumSet<E> decode(int code,
Class<E> enumType) {
try {
E[] values = (E[]) enumType.getMethod("values").invoke(null);
EnumSet<E> result = EnumSet.noneOf(enumType);
while (code != 0) {
int ordinal = Integer.numberOfTrailingZeros(code);
code ^= Integer.lowestOneBit(code);
result.add(values[ordinal]);
}
return result;
} catch (IllegalAccessException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
// Probably a NullPointerException, caused by calling this method
// from within E's initializer.
throw (RuntimeException) ex.getCause();
} catch (NoSuchMethodException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
}
}
Если вы посмотрите в исходниках на RegularEnumSet
, который является реализацией для <= 64 членов Enum, вы увидите, что он содержит:
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
*/
private long elements = 0L;
элементы - это битовая маска, в которой битовые позиции равны порядковым номерам перечисления, что именно то, что вам и нужно. Однако, этот атрибут не делается доступным через геттер или сеттер, так как он не будет соответствовать эквивалентным аксессуарам для JumboEnumSet
.
Это не одно из самых приятных решений, но если Вам нужна простота и скорость, то Вы можете создать 2 статических метода утилиты, которые извлекают и устанавливают атрибут elements
с помощью рефлексии.
Для меня, наверное, достаточно установить класс констант, содержащий значения enum в виде целочисленных констант, где я могу быть уверен, какому enum присваивается какой бит.
Хранить порядковый номер как представление EnumSet - не лучшая идея. Порядковые номера зависят от порядка определения в классе Enum (, связанное обсуждение здесь ). Ваша база данных может быть легко нарушена рефакторингом, который изменяет порядок значений Enum или вводит новые в середине.
Вы должны ввести стабильное представление отдельных значений перечисления. Это могут быть значения типа int, представленные в способе, предложенном для EnumSet .
Ваши Enums могут реализовывать интерфейсы, поэтому стабильное представление может быть непосредственно в значении перечисления (адаптировано из Адамски):
interface Stable{
int getStableId();
}
public enum X implements Stable {
A(1), B(2);
private int stableId;
X(int id){
this.stableId = id;
}
@Override public int getStableId() {
return stableId;
}
}
адаптировано из кода Адамски:
public <E extends Stable> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= (1 << val.getStableId());
}
return ret;
}
EnumSet
реализует Serializable
, но если вы используете его, то это очень накладно (он записан как массив идентификаторов, а не как BitSet
, как вы могли бы ожидать, плюс заголовок объектного потока)
Правильный способ представления коллекции из нескольких выбранных параметров - использование массива путем именования тэга SELECT суффиксом [].
Проблема в том, что он неправильно обрабатывается методом jQuery serialize ().
Для такого SELECT infact:
<select name="a[]"> <option value="five">5</option> <option value="six">6</option> <option value="seven">7</option> </select>
serialize отправляет этот массив: a [] = 0 & a [] = 1 & a [] = 2 получен PHP таким образом:
[a] => Array ( [0] => 0 [1] => 1 [2] => 2 )
, где реальные значения теряются.
-121--4749311-Пока я этого не сделал, другие пользователи Интернета, например,
Мы исследовали относительные достоинства C++ и Erlang в реализации параллельного отслеживания акустических лучей алгоритм для ВМС США. Мы нашли гораздо меньшая кривая обучения и улучшение среды отладки для параллельный эрланг, чем для программирование C++ на основе потоков. Наш Реализация C++ превзошла Программа Erlang не менее чем на 12x. Попытки использования Erlang в Камеру Микропроцессор BE был разочарован Память Эрланга. (Источник)
И что-то ближе к моему сердцу, что я помню после конкурса ICFP:
-121--865222-Кодирование было очень простым, перевод псевдокода в C++. Я мог бы использовать Java или C #, но я на точка, где программирование на высоком уровне уровень в C++ так же прост, и я хотел сохранить возможность быстрого опускаясь вниз в некоторые низкоуровневые немного трепещет, если он спустился к нему. Эрланг - мой другой любимый язык за взлом в, но беспокоился о достижении некоторой производительности проблема, которую я не смог устранить я от. (Источник)
Обеспечивая соответствие перечисления int (т.е. существует < = 32 значения), я бы свернул собственную реализацию, используя порядковое значение каждого перечисления; Например,
public <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
// Bitwise-OR each ordinal value together to encode as single int.
ret |= (1 << val.ordinal());
}
return ret;
}
public <E extends Enum<E>> EnumSet<E> decode(int encoded, Class<E> enumKlazz) {
// First populate a look-up map of ordinal to Enum value.
// This is fairly disgusting: Anyone know of a better approach?
Map<Integer, E> ordinalMap = new HashMap<Integer, E>();
for (E val : EnumSet.allOf(enumKlazz)) {
ordinalMap.put(val.ordinal(), val);
}
EnumSet<E> ret= EnumSet.noneOf(enumKlazz);
int ordinal = 0;
// Now loop over encoded value by analysing each bit independently.
// If the bit is set, determine which ordinal that corresponds to
// (by also maintaining an ordinal counter) and use this to retrieve
// the correct value from the look-up map.
for (int i=1; i!=0; i <<= 1) {
if ((i & encoded) != 0) {
ret.add(ordinalMap.get(ordinal));
}
++ordinal;
}
return ret;
}
Отказ от ответственности : Я не тестировал это!
EDIT
Как упоминает Томас в комментариях, порядковые номера нестабильны тем, что любое изменение определения перечисления в коде приведет к повреждению кодировок в базе данных (например, если вставить новое значение перечисления в середине существующего определения). Мой подход к решению этой проблемы заключается в определении таблицы «Enum» для перечисления, содержащей числовой идентификатор (, а не порядковый номер ) и значение перечисления последовательность. При запуске приложения Java первое, что делает уровень DAO, это считывает каждую таблицу Enum в память и:
Это гораздо более чистый/надежный IMHO, чем порядковый подход, который я описал выше.