Який правильний спосіб передати Int до enum в Java з урахуванням наступного enum?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Який правильний спосіб передати Int до enum в Java з урахуванням наступного enum?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Відповіді:
Спробуйте, MyEnum.values()[x]
де x
має бути 0
або 1
, тобто дійсний порядковий знак для цього перерахунку.
Зауважте, що в Java enums насправді є класами (і значення enum, таким чином, є об'єктами), і, таким чином, ви не можете закинути int
або навіть Integer
перерахувати.
MyEnum.values()
як дорогу. тобто якщо ви називаєте це сотні разів.
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;
}
}
MyEnum.values()[x]
дорогу операцію. Я не знаю, як це працює в деталях, але мені здається, що доступ до елемента в масиві не буде великим завданням, а також постійний час. Якщо масив має бути побудований, це потребує часу O (n), який є тим же часом запуску, що і ваше рішення.
values()
кожен раз генерує новий масив, оскільки масиви є мутаційними, тому не можна було б безпечно повертати той самий один раз. Оператори переключення не обов'язково O (n), вони можуть бути складені для переходу таблиць. Тож претензії Лоренцо здаються виправданими.
myEnum = myEnumValues[i]
він все одно поверне цей i
елемент у Enum без змін.
Якщо ви хочете дати цілі значення, ви можете використовувати структуру, як показано нижче
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];
}
}
values
те саме ім'я, як метод values()
. Я використовую cachedValues
для назви поля.
Переліки Java не мають такого ж типу перерахування «перерахунок до int», що вони роблять у C ++.
Однак, всі перерахунки мають values
метод, який повертає масив можливих значень enum, так що
MyEnum enumValue = MyEnum.values()[x];
повинен працювати. Це трохи неприємно, і, можливо, буде краще не намагатися перетворити з int
s на Enum
s (або навпаки), якщо можливо.
Це не те, що зазвичай робиться, тому я б передумав. Але, сказавши це, основними операціями є: int -> enum за допомогою EnumType.values () [intNum], а enum -> int за допомогою enumInst.ordinal ().
Однак, оскільки будь-яка реалізація значень () не має іншого вибору, крім того, щоб надати вам копію масиву (масиви java ніколи не є лише для читання), вам краще послужити, використовуючи EnumMap для кешування enum -> int відображення.
Ось рішення, з яким я планую піти. Це не тільки працює з непослідовними цілими числами, але має працювати з будь-яким іншим типом даних, який ви можете використовувати як базовий ідентифікатор для значень enum.
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.
clearCachedValues
коли ви закінчите його використання (що повертає приватне поле до нуля). Я вважаю MyEnum.fromInt(i)
простішим для розуміння, ніж обхід об’єкта карти.
У випадку, якщо він допомагає іншим, варіант, який я віддаю перевагу, який не вказаний тут, використовує функцію Карт 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
, будь-яку поведінку ви хочете.
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
метод.
Ви можете повторити перерахунок values()
перерахувань та порівняти ціле значення 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
сподіваюся, це допомагає;)
На основі відповіді @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());
}
}
Хороший варіант - уникнути конверсії з 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;
}
}
}
У Котліні:
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)!!
Написав цю реалізацію. Це дозволяє пропускати відсутні значення, негативні значення та зберігає код узгодженим. Карта також кешована. Використовує інтерфейс і потребує Java 8.
Енум
public enum Command implements OrdinalEnum{
PRINT_FOO(-7),
PRINT_BAR(6),
PRINT_BAZ(4);
private int val;
private Command(int val){
this.val = val;
}
public int getVal(){
return val;
}
private static Map<Integer, Command> map = OrdinalEnum.getValues(Command.class);
public static Command from(int i){
return map.get(i);
}
}
Інтерфейс
public interface OrdinalEnum{
public int getVal();
@SuppressWarnings("unchecked")
static <E extends Enum<E>> Map<Integer, E> getValues(Class<E> clzz){
Map<Integer, E> m = new HashMap<>();
for(Enum<E> e : EnumSet.allOf(clzz))
m.put(((OrdinalEnum)e).getVal(), (E)e);
return m;
}
}