IT

Int를 Java로 열거

lottoking 2020. 3. 8. 16:26
반응형

Int를 Java로 열거


다음 열거 형이 주어지면 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()[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;
        }
}

이런 식으로 시도해 볼 수 있습니다.
요소 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];
    }
}

Java 열거 형에는 C ++에서와 같은 종류의 열거 형 매핑이 없습니다.

즉, 모든 열거 형에는 values가능한 열거 형 값의 배열을 반환하는 메서드가 있으므로

MyEnum enumValue = MyEnum.values()[x];

작동해야합니다. 그것은 조금 불쾌하고 가능한 경우 s 에서 ints로 Enum또는 그 반대로 변환하지 않는 것이 좋습니다 .


이것은 일반적으로 수행되는 것이 아니므로 다시 생각할 것입니다. 그러나 기본 작업은 int-> EnumType.values ​​() [intNum]을 사용하는 enum, enumInst.ordinal ()을 사용하는 enum-> int입니다.

그러나 values ​​() 구현은 배열의 사본을 제공하는 것 외에는 선택의 여지가 없기 때문에 (자바 배열은 읽기 전용이 아닙니다) EnumMap을 사용하여 enum-> int 매핑을 캐시하는 것이 좋습니다.


사용하다 MyEnum enumValue = MyEnum.values()[x];


여기에 내가 갈 해결책이 있습니다. 이것은 비 순차 정수에서 작동 할뿐만 아니라 열거 형 값의 기본 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 클래스의 정적 멤버로 캐시 할 수 있습니다.


다른 사람들을 돕기 위해 여기에 나열되지 않은 선호하는 옵션은 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()열거 형을 반복하고 열거 형의 정수 값을 다음 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());
    }
}

코 틀린에서 :

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)!!

좋은 옵션입니다 에서 변환 intenum: 당신이 최대 값을 필요로하는 경우, 예를 들어, 당신은 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'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;
    }
}

참고 URL : https://stackoverflow.com/questions/5878952/cast-int-to-enum-in-java



반응형