Приведите Int для перечисления в Java
Как правильно преобразовать Int в перечисление в Java, учитывая следующее перечисление?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
15 ответов
Пытаться 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 не имеют того же типа сопоставления перечисления с целым, что и в C++.
Тем не менее, все перечисления имеют values
метод, который возвращает массив возможных значений перечисления, так
MyEnum enumValue = MyEnum.values()[x];
должно сработать. Это немного противно, и, возможно, лучше не пытаться конвертировать из int
с Enum
s (или наоборот), если это возможно.
Это не то, что обычно делается, поэтому я бы пересмотрел. Но, сказав это, основными операциями являются: int -> enum с использованием EnumType.values ()[intNum] и enum -> int с использованием enumInst.ordinal().
Однако, поскольку любая реализация values () не имеет другого выбора, кроме как предоставить вам копию массива (java-массивы никогда не предназначены только для чтения), вам лучше использовать EnumMap для кэширования отображения enum -> int.
Вот решение, которое я планирую использовать. Это не только работает с непоследовательными целыми числами, но и должно работать с любым другим типом данных, который вы можете использовать в качестве основного идентификатора для значений перечисления.
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;
}
}
Мне нужно только конвертировать идентификаторы в перечисления в определенное время (при загрузке данных из файла), поэтому у меня нет причин постоянно хранить карту в памяти. Если вам все время нужна карта, вы всегда можете кэшировать ее как статический член вашего класса Enum.
Основываясь на ответе @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());
}
}
В случае, если это помогает другим, предпочтительный вариант, которого здесь нет в списке, использует функциональность карт Guava:
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()
enum и сравните целочисленное значение enum с заданным 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
Надеюсь, это поможет;)
Это должно быть связано с несовпадением индексов с проблемой порядкового значения.
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's 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;
}
}
В Котлине:
enum class Status(val id: Int) {
NEW(0), VISIT(1), IN_WORK(2), FINISHED(3), CANCELLED(4), DUMMY(5);
companion object {
private val statuses = Status.values().associateBy(Status::id)
fun getStatus(id: Int): Status? = statuses[id]
}
}
Использование:
val status = Status.getStatus(1)!!
Это тот же ответ, что и у врачей, но он показывает, как устранить проблему с изменяемыми массивами. Если вы используете такой подход сначала из-за предсказания ветвлений, если эффект будет иметь очень малое значение до нуля, а весь код вызывает функцию изменяемого массива 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;
}
Хороший вариант - избегать конвертации из int
в enum
: например, если вам нужно максимальное значение, вы можете сравнить x.ordinal() с y.ordinal() и вернуть x или y соответственно. (Возможно, вам придется изменить порядок значений, чтобы сделать такое сравнение значимым.)
Если это невозможно, я бы сохранил MyEnum.values()
в статический массив.
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;
}
}
}