Попробуйте, MyEnum.values()[x]где xдолжно быть 0или 1, то есть действительный порядковый номер для этого перечисления.
Обратите внимание, что в Java перечисления на самом деле являются классами (и значения перечисления, таким образом, являются объектами), и, таким образом, вы не можете привести intили даже Integerперечислить.
+1: вы можете захотеть кэшировать MyEnum.values()как его дорого. т.е. если вы звоните это сотни раз.
Питер Лори
6
@PeterLawrey Только для полноты, вы можете объяснить, почему это должно быть медленно? Я не вижу очевидной причины для этого.
Tarrasch
48
@Tarrasch, поскольку массивы являются изменяемыми, values () должен возвращать копию массива элементов на случай, если вам случится изменить его. Создание этой копии каждый раз относительно дорого.
Питер Лори
9
@PeterLawrey В последнее время я много пользуюсь хаскелем (где все неизменно)! Спасибо за ваше ясное и краткое объяснение. :)
Tarrasch
как получить «х»?
Beeing Jk
161
MyEnum.values()[x]это дорогая операция. Если производительность вызывает беспокойство, вы можете сделать что-то вроде этого:
Если вы хотите избежать обслуживания коммутатора, то используйте класс using: private final MyEnum [] myEnumValues = MyEnum.values (); Тогда использование: myEnum = myEnumValues [i];
Гили Нахум
23
@GiliNachum сказал это странным образом, но проблема с этим решением - ремонтопригодность. Это идет вразрез с принципом DRY, который означает, что при изменении значений перечисления (переупорядочении, добавлении значений, удалении значений) оператор switch должен обновляться одновременно. Комментарий Гили вынуждает Java поддерживать согласованность со списком значений перечисления, изменения значений перечисления не влияют на этот подход вообще.
Дандре Эллисон
3
@LorenzoPolidori, Можете ли вы объяснить, почему вы считаете MyEnum.values()[x]дорогой операцией. Я не знаю, как это работает в деталях, но мне кажется, что доступ к элементу в массиве не будет большой проблемой, то есть постоянным временем. Если массив должен быть собран, это занимает O (n) время, то есть то же время выполнения, что и ваше решение.
Brunsgaard
1
@brunsgaard Я полагаю, values()каждый раз генерируется новый массив, потому что массивы изменчивы, поэтому было бы небезопасно возвращать один и тот же один раз несколько раз. Операторы switch не обязательно O (n), они могут быть скомпилированы для перехода по таблицам. Таким образом, претензии Лоренцо кажутся оправданными.
MikeFHay
1
Версия @Johnson Gili не требует каких-либо дополнительных изменений кода, кроме изменений в объявлении Enum. Если вы добавите новый элемент в enum, myEnum = myEnumValues[i]все равно вернете этот iэлемент в Enum без изменений.
Дандре Эллисон
45
Если вы хотите дать целочисленные значения, вы можете использовать структуру, как показано ниже
publicenum A
{
B(0),
C(10),None(11);int id;private A(int i){id = i;}publicintGetID(){return id;}publicbooleanIsEmpty(){returnthis.equals(A.None);}publicbooleanCompare(int i){return id == i;}publicstatic A GetValue(int _id){
A[]As= A.values();for(int i =0; i <As.length; i++){if(As[i].Compare(_id))returnAs[i];}return A.None;}}
+1, потому что это подчеркивает тот факт, что значения не должны быть последовательными.
Равин
Кроме того, это, кажется, единственный ответ, который работает, если вы хотите разреженный (или повторяющийся) набор целочисленных значений вместо использования порядковых номеров по умолчанию от 0 .. (count-1). Это может быть важно, если вы взаимодействуете с существующим кодом, например, по сети.
benkc
Стоит отметить, что, как и в приведенных выше ответах, кэширование результата values (), вероятно, имеет смысл, чтобы избежать выделения памяти и копирования массива при каждом его вызове.
benkc
1
И, в зависимости от длины вашего перечисления, вы можете захотеть создать HashMap или использовать бинарный поиск или что-то для этого поиска, вместо того, чтобы выполнять линейный поиск каждый раз.
benkc
2
Это должно быть правильным способом и наилучшей практикой для преобразования int в enum, и я думаю, что вы можете упростить проблему с помощью общедоступной статической функции GetValue (int _id) {for (A a: A.values () {if (a.getId ( ) == _ id) {return a;}} return null;} Избавьтесь от None, isEmpty () и compare ()
Chris.Zou
35
Вы можете попробовать вот так.
Создать класс с идентификатором элемента.
publicEnumMyEnum{
THIS(5),
THAT(16),
THE_OTHER(35);privateint id;// Could be other data type besides intprivateMyEnum(int id){this.id = id;}publicstaticMyEnum fromId(int id){for(MyEnum type : values()){if(type.getId()== id){return type;}}returnnull;}}
Это решение я использую сейчас. Но ИМХО это менее запутанно, если вы не дадите полю valuesто же имя, что и метод values(). Я использую cachedValuesдля имени поля.
ToolmakerSteve
2
Эффективный и элегантный; скопировал и вставил в мой проект :) Единственное, что я изменил, это fromInt (int i), который я только что вызвал из (int i), потому что немного избыточно иметь int дважды в сигнатуре.
pipedreambomb
1
почему не инициализировать с начала? зачем ждать первого удара?
Кайзер
9
Перечисления Java не имеют того же типа сопоставления перечисления с целым, что и в C ++.
Тем не менее, все перечисления имеют valuesметод, который возвращает массив возможных значений перечисления, поэтому
MyEnum enumValue =MyEnum.values()[x];
должно сработать. Это немного неприятно, и, возможно, лучше не пытаться конвертировать из ints в Enums (или наоборот), если это возможно.
Это не то, что обычно делается, поэтому я бы пересмотрел. Но, сказав это, основными операциями являются: int -> enum с использованием EnumType.values () [intNum] и enum -> int с использованием enumInst.ordinal ().
Однако, поскольку любая реализация values () не имеет другого выбора, кроме как предоставить вам копию массива (java-массивы никогда не доступны только для чтения), вам лучше использовать EnumMap для кэширования отображения enum -> int.
Re "Это не то, что обычно делается": Общий случай, когда это полезно: enum соответствует значениям int, хранящимся в базе данных.
ToolmakerSteve
@ ToolmakerSteve вы абсолютно правы в том, что сопоставления необходимы. Но хотите ли вы оставить такую кодировку для какого-либо средства отображения или набора инструментов / библиотеки?
Дилум Ранатунга
7
использование MyEnum enumValue = MyEnum.values()[x];
Вот решение, которое я планирую использовать. Это не только работает с непоследовательными целыми числами, но и должно работать с любым другим типом данных, который вы можете использовать в качестве основного идентификатора для значений перечисления.
publicEnumMyEnum{
THIS(5),
THAT(16),
THE_OTHER(35);privateint id;// Could be other data type besides intprivateMyEnum(int id){this.id = id;}publicint getId(){returnthis.id;}publicstaticMap<Integer,MyEnum> buildMap(){Map<Integer,MyEnum> map =newHashMap<Integer,MyEnum>();MyEnum[] values =MyEnum.values();for(MyEnum value : values){
map.put(value.getId(), value);}return map;}}
Мне нужно только конвертировать идентификаторы в перечисления в определенное время (при загрузке данных из файла), поэтому у меня нет причин постоянно хранить карту в памяти. Если вам все время нужна карта, вы всегда можете кэшировать ее как статический член вашего класса Enum.
ИМХО, если бы меня беспокоило использование памяти, я бы динамически создал HashMap-подобный @ossys, но с другим кодом, когда кеш нулевой, а затем добавил бы второй метод, clearCachedValuesкогда вы закончили с его использованием (который устанавливает приватное поле обратно в ноль). Я считаю, что MyEnum.fromInt(i)легче понять, чем обойти объект карты.
ToolmakerSteve
6
В случае, если это помогает другим, предпочтительный вариант, которого здесь нет в списке, использует функциональность карт Guava :
По умолчанию вы можете использовать null, вы можете throw IllegalArgumentExceptionили можете fromIntвернуть Optionalлюбое поведение, которое вы предпочитаете.
Вы должны упомянуть, что вы используете гуаву. Или вы можете использовать потоки:Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
shmosel
1
Возможно, захотите определить getValue()метод также.
Шмосел
@shmosel Упс, я пропустил функцию getValue, спасибо. Ввод общих версий в stackoverflow не всегда удастся. Добавлен комментарий об использовании гуавы со ссылкой. Предпочитаю метод Гуава для потоков.
Чад Бефус
4
Вы можете перебирать values()enum и сравнивать целочисленные значения enum с данными, idкак показано ниже:
publicenumTestEnum{None(0),Value1(1),Value2(2),Value3(3),Value4(4),Value5(5);privatefinalint value;privateTestEnum(int value){this.value = value;}publicint getValue(){return value;}publicstaticTestEnum getEnum(int value){for(TestEnum e:TestEnum.values()){if(e.getValue()== value)return e;}returnTestEnum.None;//For values out of enum scope}}
И используйте так: TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
надеюсь, это поможет;)
Хороший вариант - избегать конвертации intвenum : например, если вам нужно максимальное значение, вы можете сравнить x.ordinal () с y.ordinal () и вернуть x или y соответственно. (Возможно, вам придется изменить порядок значений, чтобы сделать такое сравнение значимым.)
Если это невозможно, я бы MyEnum.values()сохранил статический массив.
Если вы получаете int из DB и хотите преобразовать его в Enum, что, как мне кажется, является очень распространенной задачей, вам потребуется преобразование int -> enum, IMO ..
Yuki Inoue
0
Это тот же ответ, что и у врачей, но он показывает, как устранить проблему с изменяемыми массивами. Если вы используете такой подход сначала из-за предсказания ветвлений, если эффект будет иметь очень малое значение до нуля, а весь код вызывает функцию изменяемого массива values () только один раз. Поскольку обе переменные являются статическими, они не будут использовать n * памяти для каждого использования этого перечисления.
privatestaticboolean arrayCreated =false;privatestaticRFMsgType[]ArrayOfValues;publicstaticRFMsgTypeGetMsgTypeFromValue(intMessageID){if(arrayCreated ==false){ArrayOfValues=RFMsgType.values();}for(int i =0; i <ArrayOfValues.length; i++){if(ArrayOfValues[i].MessageIDValue==MessageID){returnArrayOfValues[i];}}returnRFMsgType.UNKNOWN;}
Написал эту реализацию. Он учитывает пропущенные значения, отрицательные значения и поддерживает согласованность кода. Карта также кэшируется. Использует интерфейс и нуждается в Java 8.
Ответы:
Попробуйте,
MyEnum.values()[x]
гдеx
должно быть0
или1
, то есть действительный порядковый номер для этого перечисления.Обратите внимание, что в Java перечисления на самом деле являются классами (и значения перечисления, таким образом, являются объектами), и, таким образом, вы не можете привести
int
или дажеInteger
перечислить.источник
MyEnum.values()
как его дорого. т.е. если вы звоните это сотни раз.MyEnum.values()[x]
это дорогая операция. Если производительность вызывает беспокойство, вы можете сделать что-то вроде этого:источник
MyEnum.values()[x]
дорогой операцией. Я не знаю, как это работает в деталях, но мне кажется, что доступ к элементу в массиве не будет большой проблемой, то есть постоянным временем. Если массив должен быть собран, это занимает O (n) время, то есть то же время выполнения, что и ваше решение.values()
каждый раз генерируется новый массив, потому что массивы изменчивы, поэтому было бы небезопасно возвращать один и тот же один раз несколько раз. Операторы switch не обязательно O (n), они могут быть скомпилированы для перехода по таблицам. Таким образом, претензии Лоренцо кажутся оправданными.myEnum = myEnumValues[i]
все равно вернете этотi
элемент в Enum без изменений.Если вы хотите дать целочисленные значения, вы можете использовать структуру, как показано ниже
источник
Вы можете попробовать вот так.
Создать класс с идентификатором элемента.
Теперь выберите этот Enum, используя id как int.
источник
Я кеширую значения и создаю простой метод статического доступа:
источник
values
то же имя, что и методvalues()
. Я используюcachedValues
для имени поля.Перечисления Java не имеют того же типа сопоставления перечисления с целым, что и в C ++.
Тем не менее, все перечисления имеют
values
метод, который возвращает массив возможных значений перечисления, поэтомудолжно сработать. Это немного неприятно, и, возможно, лучше не пытаться конвертировать из
int
s вEnum
s (или наоборот), если это возможно.источник
Это не то, что обычно делается, поэтому я бы пересмотрел. Но, сказав это, основными операциями являются: int -> enum с использованием EnumType.values () [intNum] и enum -> int с использованием enumInst.ordinal ().
Однако, поскольку любая реализация values () не имеет другого выбора, кроме как предоставить вам копию массива (java-массивы никогда не доступны только для чтения), вам лучше использовать EnumMap для кэширования отображения enum -> int.
источник
использование
MyEnum enumValue = MyEnum.values()[x];
источник
Вот решение, которое я планирую использовать. Это не только работает с непоследовательными целыми числами, но и должно работать с любым другим типом данных, который вы можете использовать в качестве основного идентификатора для значений перечисления.
Мне нужно только конвертировать идентификаторы в перечисления в определенное время (при загрузке данных из файла), поэтому у меня нет причин постоянно хранить карту в памяти. Если вам все время нужна карта, вы всегда можете кэшировать ее как статический член вашего класса Enum.
источник
clearCachedValues
когда вы закончили с его использованием (который устанавливает приватное поле обратно в ноль). Я считаю, чтоMyEnum.fromInt(i)
легче понять, чем обойти объект карты.В случае, если это помогает другим, предпочтительный вариант, которого здесь нет в списке, использует функциональность карт Guava :
По умолчанию вы можете использовать
null
, вы можетеthrow IllegalArgumentException
или можетеfromInt
вернутьOptional
любое поведение, которое вы предпочитаете.источник
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
метод также.Вы можете перебирать
values()
enum и сравнивать целочисленные значения enum с данными,id
как показано ниже:И используйте так:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
надеюсь, это поможет;)
источник
Основываясь на ответе @ChadBefus и комментарии @shmosel, я бы рекомендовал использовать это. (Эффективный поиск и работает на чистой Java> = 8)
источник
Хороший вариант - избегать конвертации
int
вenum
: например, если вам нужно максимальное значение, вы можете сравнить x.ordinal () с y.ordinal () и вернуть x или y соответственно. (Возможно, вам придется изменить порядок значений, чтобы сделать такое сравнение значимым.)Если это невозможно, я бы
MyEnum.values()
сохранил статический массив.источник
Это тот же ответ, что и у врачей, но он показывает, как устранить проблему с изменяемыми массивами. Если вы используете такой подход сначала из-за предсказания ветвлений, если эффект будет иметь очень малое значение до нуля, а весь код вызывает функцию изменяемого массива values () только один раз. Поскольку обе переменные являются статическими, они не будут использовать n * памяти для каждого использования этого перечисления.
источник
источник
В Котлине:
Использование:
источник
Написал эту реализацию. Он учитывает пропущенные значения, отрицательные значения и поддерживает согласованность кода. Карта также кэшируется. Использует интерфейс и нуждается в Java 8.
Enum
Интерфейс
источник