Каков правильный способ преобразования Int в enum в Java с учетом следующего перечисления?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Каков правильный способ преобразования Int в enum в Java с учетом следующего перечисления?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Попробуйте MyEnum.values()[x]
, где x
должен быть 0
или 1
, то есть действительный порядковый номер для этого перечисления.
Обратите внимание, что в Java перечисления на самом деле являются классами (и значения перечисления, таким образом, являются объектами), и поэтому вы не можете передать int
или даже Integer
в перечисление.
MyEnum.values()[x]
- дорогостоящая операция. Если производительность является проблемой, вы можете сделать что-то вроде этого:
public enum MyEnum {
EnumValue1,
EnumValue2;
public static MyEnum fromInteger(int x) {
switch(x) {
case 0:
return EnumValue1;
case 1:
return EnumValue2;
}
return null;
}
}
Если вы хотите указать целые значения, вы можете использовать структуру, как показано ниже
public enum A
{
B(0),
C(10),
None(11);
int id;
private A(int i){id = i;}
public int GetID(){return id;}
public boolean IsEmpty(){return this.equals(A.None);}
public boolean Compare(int i){return id == i;}
public static A GetValue(int _id)
{
A[] As = A.values();
for(int i = 0; i < As.length; i++)
{
if(As[i].Compare(_id))
return As[i];
}
return A.None;
}
}
Вы можете попробовать это.
Создать класс с идентификатором элемента.
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public static MyEnum fromId(int id) {
for (MyEnum type : values()) {
if (type.getId() == id) {
return type;
}
}
return null;
}
}
Теперь выберите этот Enum, используя id как int.
MyEnum myEnum = MyEnum.fromId(5);
Я кэширую значения и создаю простой метод статического доступа:
public static enum EnumAttributeType {
ENUM_1,
ENUM_2;
private static EnumAttributeType[] values = null;
public static EnumAttributeType fromInt(int i) {
if(EnumAttributeType.values == null) {
EnumAttributeType.values = EnumAttributeType.values();
}
return EnumAttributeType.values[i];
}
}
В перечислениях Java нет такого же типа отображения enum-to-int, что и в С++.
Тем не менее, все перечисления имеют метод values
, который возвращает массив возможных значений перечисления, поэтому
MyEnum enumValue = MyEnum.values()[x];
должен работать. Это немного неприятно, и было бы лучше не пытаться конвертировать из int
в Enum
(или наоборот), если это возможно.
Это не то, что обычно делается, поэтому я бы пересмотрел. Но, сказав это, основными операциями являются: int → enum, используя EnumType.values () [intNum], и enum → int, используя enumInst.ordinal().
Однако, поскольку любая реализация значений() не имеет другого выбора, кроме как предоставить вам копию массива (массивы java никогда не доступны только для чтения), вам лучше будет использовать EnumMap для кэширования перечисления → int отображение.
Используйте MyEnum enumValue = MyEnum.values()[x];
Вот решение, с которым я планирую пойти. Это не только работает с непоследовательными целыми числами, но и должно работать с любым другим типом данных, который вы можете использовать в качестве базового идентификатора для своих значений перечисления.
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public static Map<Integer, MyEnum> buildMap() {
Map<Integer, MyEnum> map = new HashMap<Integer, MyEnum>();
MyEnum[] values = MyEnum.values();
for (MyEnum value : values) {
map.put(value.getId(), value);
}
return map;
}
}
Мне нужно только преобразовать id в перечисления в определенное время (при загрузке данных из файла), поэтому нет никаких оснований для того, чтобы я всегда сохранял карту в памяти. Если вам нужна карта, чтобы быть доступной во все времена, вы всегда можете кэшировать ее как статический член вашего класса Enum.
В случае, если это помогает другим, вариант, который я предпочитаю, который не указан здесь, использует функциональные возможности Guava Maps:
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static ImmutableMap<Integer, MyEnum> reverseLookup =
Maps.uniqueIndex(Arrays.asList(MyEnum.values())), MyEnum::getValue);
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
}
По умолчанию вы можете использовать null
, вы можете throw IllegalArgumentException
или ваш fromInt
может вернуть Optional
, независимо от того, какое поведение вы предпочитаете.
Вы можете перечислить значение values()
для перечисления и сравнить целочисленное значение перечисления с заданным id
, как показано ниже:
public enum TestEnum {
None(0),
Value1(1),
Value2(2),
Value3(3),
Value4(4),
Value5(5);
private final int value;
private TestEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static TestEnum getEnum(int value){
for (TestEnum e:TestEnum.values()) {
if(e.getValue() == value)
return e;
}
return TestEnum.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()
в статическом массиве.
Это тот же самый ответ, что и врачи, но он показывает, как устранить проблему с изменяемыми массивами. Если вы используете такой подход из-за предварительного предсказания ветвления, если у него будет очень мало нулевого эффекта, а весь код вызывает только функцию изменяемых значений массива() только один раз. Поскольку обе переменные являются статическими, они не будут потреблять n * память для каждого использования этого перечисления.
private static boolean arrayCreated = false;
private static RFMsgType[] ArrayOfValues;
public static RFMsgType GetMsgTypeFromValue(int MessageID) {
if (arrayCreated == false) {
ArrayOfValues = RFMsgType.values();
}
for (int i = 0; i < ArrayOfValues.length; i++) {
if (ArrayOfValues[i].MessageIDValue == MessageID) {
return ArrayOfValues[i];
}
}
return RFMsgType.UNKNOWN;
}
enum MyEnum {
A(0),
B(1);
private final int value;
private MyEnum(int val) {this.value = value;}
private static final MyEnum[] values = MyEnum.values();//cache for optimization
public static final getMyEnum(int value) {
try {
return values[value];//OOB might get triggered
} catch (ArrayOutOfBoundsException e) {
} finally {
return myDefaultEnumValue;
}
}
}
Это должно привести к тому, что индексы не синхронизируются с проблемой порядкового значения.
package service.manager;
public enum Command {
PRINT_FOO(0),
PRINT_BAR(2),
PRINT_BAZ(3);
public int intVal;
Command(int intVal){
this.intVal = intVal;
}
/**
* Functionality to ascertain an enum from an int
* The static block initializes the array indexes to correspond with it according ordinal value
* Simply use Command.values[index] or get the int value by e.g. Command.PRINT_FOO.intVal;
* */
public static Command values[];
static{
int maxVal = -1;
for(Command cmd : Command.values())
if(maxVal < cmd.intVal)
maxVal = cmd.intVal;
values = new Command[maxVal + 1];
for(Command cmd : Command.values())
values[cmd.intVal] = cmd;
}
}
Основываясь на ответе @ChadBefus и комментарии @shmosel, я бы рекомендовал использовать это. (Эффективный поиск и работает на чистом java> = 8)
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Map;
import java.util.Arrays;
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static Map<Integer, MyEnum> reverseLookup =
Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
public static void main(String[] args) {
System.out.println(fromInt(-66).toString());
}
}