Когда определены значения enum?
Я пытаюсь реализовать что-то полуэффективно. В моей программе есть перечислитель, представляющий метрики, которые используются для передачи информации в программе.
У меня есть класс, который позволяет мне "объединять" эти метрики в один объект, чтобы я мог по существу создать "предложение", чтобы дать мне сложную информацию без необходимости какого-либо сложного анализа информации. По сути, это битовые флаги, но поскольку я использую enum, их может быть больше, чем 64.
Проблема в том, что если я много раз создаю экземпляры этого класса-контейнера и я собираюсь создать массив следующим образом:
metrics = new boolean[Metrics.values().length];
Я чувствую, что создание массива перечисленных значений так часто, чтобы просто запросить его размер, расточительно. Мне интересно, можно ли просто определить размер перечисляемых значений() в статическом контексте, чтобы это постоянное значение, которое мне не нужно пересчитывать:
private static final int METRIC_COUNT = Metrics.values().length;
Я могу это сделать? Или компилятор не определил перечисленные значения до того, как объявил эту статическую переменную? Я знаю, что это не лучшее объяснение моего вопроса, но я не уверен, как еще это сформулировать.
Я знаю, что статическая переменная будет определена во время выполнения (если назначенное ей значение не было буквальным значением), поэтому сможет ли программа запрашивать членов перечисления Metrics в этот момент выполнения?
Ответы
Ответ 1
EnumSet
"объединить" эти метрики в один объект
по сути битовые флаги
Похоже, вам нужен битовый массив, с битом, перевернутым для наличия/отсутствия каждого предопределенного значения перечисления.
Если это так, нет необходимости кататься самостоятельно. Используйте EnumSet
или EnumMap
. Это специальные реализации интерфейсов Set
и Map
. Эти классы чрезвычайно эффективны из-за того, что они обрабатывают перечисления природы, занимают очень мало памяти и очень быстро выполняются.
Взять, к примеру, встроенное перечисление DayOfWeek
. Определяет семь объектов, по одному на каждый день недели в календаре ISO 8601.
Set< DayOfWeek > weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY ) ;
Используйте удобные методы Set
такие как contains
.
boolean isTodayWeekend = weekend.contains( LocalDate.now().getDayOfWeek() ) ;
Если вы зацикливаете элементы набора, их обещают предоставить в том порядке, в котором они определены в перечислении (их "естественный" порядок). Таким образом, по логике EnumSet
, EnumSet
должен был быть помечен как SortedSet
, но загадочным образом не был так помечен. Тем не менее, вы знаете порядок. Например, цикл EnumSet.allOf( DayOfWeek.class )
отображает DayOfWeek.MONDAY
сначала, а DayOfWeek.SUNDAY
последний (согласно стандарту ISO 8601).
Когда определены значения Enum?
Элементы enum
определяются во время компиляции и не могут быть изменены во время выполнения (если вы не используете трюки с отражением). Каждая именованная переменная заполняется экземпляром при загрузке класса. См. Раздел 8.9, Типы перечислений спецификации языка Java.
Если вы определите enum Pet
с помощью DOG
, CAT
и BIRD
, то вы будете знать, что у вас будет ровно три экземпляра во время выполнения.
Вы можете посчитать количество элементов, определенных в перечислении, как минимум двумя способами:
- Вызов метода
values
сгенерированного компилятором для любого enum
, где вы можете задать размер результирующего массива, как показано в вашем Вопросе.
int countDows = DayOfWeek.values().length() ;
- Вызов
Set::size
после создания EnumSet
всех экземпляров перечисления.
int countDows = EnumSet.allOf( DayOfWeek.class).size() ;
Ответ 2
private static final int METRIC_COUNT = Metrics.values().length;
Я могу это сделать?
Да, ты можешь. Это абсолютно правильный способ кэширования длины и обеспечения ее вычисления только один раз.
Я знаю, что статическая переменная будет определена во время выполнения (если назначенное ей значение не было буквальным значением), поэтому сможет ли программа запрашивать членов перечисления Metrics в этот момент выполнения?
Ага. Как определено, METRIC_COUNT
также вычисляется во время выполнения.
Ответ 3
Я не знаю, нужно ли вам делать это в этом случае, но я думаю, что понимаю более общую проблему неспособности вычислить константу в начале выполнения. У меня была эта проблема. Решение, которое я использовал, выглядит примерно так: вычислите METRICS_COUNT позже, когда вы будете готовы его использовать и уверены, что объект Metrics определен, но все же только один раз:
private static int METRIC_COUNT = -1;
public static int getMetricsCount() {
if (METRIC_COUNT < 0)
METRIC_COUNT = Metrics.values().length;
return METRIC_COUNT;
}
Обратите внимание, что я не рассматриваю проблему Enum конкретно, как и другие в комментариях. Я просто предлагаю способ отложить установку глобального значения до того момента, когда это необходимо.