给定以下枚举,将Int强制转换为Java中的枚举的正确方法是什么?

评论

@RyuS。那不是这个问题的重复,

#1 楼

尝试MyEnum.values()[x],其中x必须是01,即该枚举的有效序数。

请注意,在Java中,枚举实际上是类(并且枚举值因此是对象),因此您无法将int甚至Integer转换为枚举。

评论


+1:您可能希望将MyEnum.values()缓存为昂贵的缓存。也就是说,如果您拨打数百次。

– Peter Lawrey
2011年5月4日7:27

@PeterLawrey为了完整起见,您能解释一下为什么它应该很慢吗?我认为没有明显的原因。

–塔拉施
2012年12月4日,0:10

@Tarrasch因为数组是可变的,所以values()必须返回元素数组的副本,以防万一您更改它。每次创建此副本都是相对昂贵的。

– Peter Lawrey
2012年12月4日在8:44

@PeterLawrey我最近已经习惯了很多haskell(一切都是不可变的)!感谢您简洁明了的解释。 :)

–塔拉施
2012年12月4日17:46

如何获得“ x”?

– Beek Jk
17-10-5在4:41

#2 楼

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;
    }
}


评论


如果要避免进行开关维护,请在using类上:private final MyEnum [] myEnumValues = MyEnum.values();然后的用法:myEnum = myEnumValues [i];

– Gili Nachum
2012年6月4日18:20



@GiliNachum说的很奇怪,但是这个解决方案的问题是可维护性。它违反了DRY原理,这意味着每当枚举值发生更改(重新排序,添加值,删除值)时,switch语句都必须同时更新。 Gili的评论迫使Java保持与枚举值列表的一致性,对枚举值的更改完全不会影响该方法。

–丹德里·艾莉森(Dandre Allison)
13年1月8日在22:39

@LorenzoPolidori,您能解释一下为什么您将MyEnum.values()[x]视为昂贵的操作。我不知道它是如何工作的,但是对我来说,访问数组中的元素似乎没什么大不了的,也就是恒定的时间。如果必须构建阵列,则需要O(n)时间,这与您的解决方案的运行时间相同。

– Brunsgaard
13-10-4在18:06



@brunsgaard我假设每次值()都会生成一个新数组,因为数组是可变的,因此多次返回相同的数组并不安全。 switch语句不一定是O(n),它们可以编译为跳转表。因此,洛伦佐的主张似乎是合理的。

– MikeFHay
2014年1月24日在16:41

@Johnson Gili的版本不需要在Enum声明中进行任何更改即可。如果将新项目添加到枚举,则myEnum = myEnumValues [i]仍将返回枚举中的第i个项目,而无需进行任何更改。

–丹德里·艾莉森(Dandre Allison)
20 Feb 10'在2:08

#3 楼

如果要给出整数值,则可以使用以下结构

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;
        }
}


评论


+1是因为它强调了一个事实,即值不必是连续的。

–rhavin
13年2月6日在17:00

此外,如果您想要稀疏(或重复)的整数值集,而不是使用0 ..(count-1)的默认序数,则这似乎是唯一可行的答案。如果您要与现有代码交互(例如通过网络),那可能很重要。

– Benkc
13年4月22日在22:51

值得指出的是,如上述答案所示,缓存values()的结果可能是值得的,这样可以避免每次调用时分配内存和进行数组复制。

– Benkc
13年4月22日在22:52

并且,根据枚举的长度,您可能想要创建一个HashMap或使用二进制搜索或其他方式进行此查找,而不是每次都执行线性搜索。

– Benkc
13年4月22日在22:57

这应该是将int转换为枚举的正确方法和最佳实践,我认为您可以通过公共静态A GetValue(int _id){for(A a:A.values(){if(a.getId( )== _ id){return a;}}返回null;}摆脱None,isEmpty()和compare()的东西。

–邹Chris
2014年5月13日,3:15



#4 楼

您可以尝试这样。
使用元素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作为整数获取此枚举。

MyEnum myEnum = MyEnum.fromId(5);


#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()相同的名称,那么混乱就更少了。我使用cachedValues作为字段名。

–ToolmakerSteve
2015年6月27日,1:15

高效典雅;复制并粘贴到我的项目中:)我唯一更改的是fromInt(int i),我将其简称为from(int i),因为在签名中具有两次int有点多余。

– Pipedreambomb
17年5月18日在16:05

为什么不从头开始初始化?为什么要等待第一击?

– kaiser
18-2-15在23:41

#6 楼

Java枚举没有在C ++中进行的那种枚举到整数的映射。 br />
MyEnum enumValue = MyEnum.values()[x];


应该可以工作。有点讨厌,如果可能,最好不要尝试从values s转换为int s(反之亦然)。

#7 楼

这不是通常要做的事情,所以我会重新考虑。但话虽如此,基本操作是:int->使用EnumType.values()[intNum]进行枚举,以及enum->使用enumInst.ordinal()进行int编程。

values()的实现别无选择,只能给您一个数组的副本(java数组绝不是只读的),最好使用EnumMap来缓存枚举-> int映射。

评论


关于“这不是通常要做的事情”:有用的常见情况:枚举对应于存储在数据库中的int值。

–ToolmakerSteve
15年6月27日在1:09

@ToolmakerSteve,您对映射是绝对正确的。但是,您是否想将这种编码留给某些O-R映射器或某些工具箱/库?

– Dilum Ranatunga
15年8月19日在7:26

#8 楼

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

#9 楼

这是我计划使用的解决方案。这不仅适用于非顺序整数,而且还应与您可能希望用作枚举值的基础ID的任何其他数据类型一起使用。
>我只需要在特定时间(从文件中加载数据时)将id转换为枚举,因此没有理由让我始终将Map保留在内存中。如果确实需要始终可访问地图,则可以始终将其作为Enum类的静态成员进行缓存。

评论


恕我直言,如果我担心内存使用情况,我将动态创建HashMap-类似于@ossys,但是当缓存为null时使用不同的代码,然后在使用完后添加第二个方法clearCachedValues(将私有字段设置回null) 。我认为MyEnum.fromInt(i)比传递地图对象更容易理解。

–ToolmakerSteve
2015年6月27日在1:23



#10 楼

如果它对其他人有帮助,我更喜​​欢的选项(此处未列出)使用Guava的Maps功能:

或您的null可以返回throw IllegalArgumentException,无论您喜欢哪种行为。

评论


您应该提到您正在使用番石榴。或者您可以使用流:Map reverseLookup = Arrays.stream(MyEnum.values())。collect(Collectors.toMap(MyEnum :: getValue,Function.identity()));

– shmosel
17年11月16日0:53



可能还想定义一个getValue()方法。

– shmosel
17年11月16日在0:55

@shmosel糟糕,我错过了getValue函数,谢谢。将通用版本输入stackoverflow并不总是会成功。添加了有关通过链接使用番石榴的评论。首选番石榴方法而不是流方法。

–乍得·贝弗斯(Chad Befus)
17年11月16日在1:15

#11 楼

您可以遍历enum的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
我希望这样帮助;)

#12 楼

基于@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());
    }
}


#13 楼

编写了此实现。它允许缺失值,负值并保持代码一致。该地图也被缓存。使用接口并需要Java8。

枚举

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;
    }
}


#14 楼

一个不错的选择是避免从int转换为enum:例如,如果需要最大值,则可以将x.ordinal()与y.ordinal()比较,并相应地返回x或y。 (您可能需要重新排序值才能使这种比较有意义。)

如果这不可能,我会将MyEnum.values()存储到静态数组中。

评论


如果您从数据库获取int并将其转换为Enum(我认为这是非常常见的任务),则需要int->枚举转换,IMO。

–井上由纪(Yuki Inoue)
18/12/2在5:41

#15 楼

这是与医生相同的答案,但它显示了如何消除可变阵列的问题。如果由于分支预测而首先使用这种方法,则效果几乎没有到零,并且整个代码仅调用一次可变数组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;
}


#16 楼

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;
        }
    }
}


评论


不要使用异常代替边界检查。

– shmosel
17年11月16日在1:19



@shmosel我认为,如果越界越少,则异常会好得多。

–佐索
17年11月17日在14:37

您的信念基于什么?

– shmosel
17年11月17日在16:59

#17 楼

在Kotlin中:

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