다음 열거 형이 주어지면 Java에서 Int를 열거 형으로 캐스팅하는 올바른 방법은 무엇입니까?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
다음 열거 형이 주어지면 Java에서 Int를 열거 형으로 캐스팅하는 올바른 방법은 무엇입니까?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
답변:
시도 MyEnum.values()[x]
곳 x
이어야 0
또는 1
그 열거에 대한 올바른 순서, 즉.
Java 열거 형은 실제로 클래스이며 따라서 열거 형 값은 객체이므로 열거 형 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
됩니다.
정수 값을 지정하려면 다음과 같은 구조를 사용할 수 있습니다
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;
}
}
이렇게 시도해 볼 수 있습니다.
요소 ID로 클래스를 작성하십시오.
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;
}
}
이제 id를 int로 사용하여이 Enum을 가져옵니다.
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
에 method와 같은 이름을 지정 하지 않으면 혼동이 줄어 듭니다 values()
. cachedValues
필드 이름으로 사용 합니다.
이것은 일반적으로 수행되는 것이 아니므로 다시 고려할 것입니다. 그러나 기본 작업은 int-> EnumType.values () [intNum]을 사용하는 enum, enumInst.ordinal ()을 사용하는 enum-> int입니다.
그러나 values () 구현은 배열의 사본을 제공하는 것 외에는 선택의 여지가 없기 때문에 (자바 배열은 읽기 전용이 아닙니다) EnumMap을 사용하여 enum-> int 매핑을 캐시하는 것이 더 좋습니다.
여기에 내가 갈 해결책이 있습니다. 이것은 비 순차 정수에서도 작동 할뿐만 아니라 열거 형 값의 기본 ID로 사용하려는 다른 데이터 형식에서도 작동합니다.
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 클래스의 정적 멤버로 캐시 할 수 있습니다.
clearCachedValues
합니다 (비공개 필드를 다시 null로 설정). 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()
열거 형을 반복하고 열거 형의 정수 값을 다음 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;
}
}
}
이 구현을 작성했습니다. 결 측값, 음수 값을 허용하고 코드 일관성을 유지합니다. 맵도 캐시됩니다. 인터페이스를 사용하며 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;
}
}