在Java中将Int转换为枚举

Max*_*ich 317 java enums casting ordinal

在给定以下枚举的情况下,将Int转换为枚举的正确方法是什么?

public enum MyEnum
{
    EnumValue1,
    EnumValue2
}


MyEnum enumValue = (MyEnum) x; //Doesn't work???
Run Code Online (Sandbox Code Playgroud)

Tho*_*mas 565

尝试必须在MyEnum.values()[x]哪里或,即该枚举的有效序数.x01

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

  • +1:您可能希望将"MyEnum.values()"缓存为昂贵的.即如果你称之为数百次. (111认同)
  • @Tarrasch作为数组是可变的,values()必须返回元素数组的副本,以防万一你碰巧改变它.每次创建此副本相对昂贵. (47认同)
  • @PeterLawrey我最近一直在使用很多haskell(一切都是不可变的)!感谢您的简明扼要的解释.:) (9认同)
  • @PeterLawrey为了完整起见,你能解释为什么它应该慢吗?我认为没有明显的理由. (6认同)

Lor*_*ori 154

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你想避免交换机维护,那么就使用class:private final MyEnum [] myEnumValues = MyEnum.values(); 然后用法:myEnum = myEnumValues [i]; (41认同)
  • @GiliNachum以一种奇怪的方式说它,但这个解决方案的问题是可维护性.它违反了DRY原则,这意味着只要更改枚举值(重新排序,添加值,删除值),就必须同时更新switch语句.Gili的评论强制Java保持与枚举值列表的一致性,对枚举值的更改根本不会影响该方法. (22认同)
  • @LorenzoPolidori,你能解释为什么你认为`MyEnum.values()[x]`是一项昂贵的操作.我不知道它的细节是如何工作的,但对我来说,访问数组中的元素似乎没什么大不了的,也就是说时间不变.如果必须构建阵列,则需要O(n)时间,这与您的解决方案的运行时间相同. (3认同)
  • @brunsgaard 我假设 `values()` 每次都会生成一个新数组,因为数组是可变的,因此多次返回相同的数组是不安全的。switch语句不一定是O(n),它们可以编译为跳转表。所以洛伦佐的说法似乎是有道理的。 (2认同)

Doc*_*tor 45

如果要提供整数值,可以使用如下结构

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;
        }
}
Run Code Online (Sandbox Code Playgroud)

  • +1因为它突出了这个事实,价值不必是连续的. (5认同)
  • 这应该是将 int 转换为 enum 的正确方法和最佳实践,我认为您可以通过 public static A GetValue(int _id) { for(A a:A.values() { if(a.getId() )==_id) { return a; }} return null; } 去掉 None、isEmpty() 和 compare() 的东西。 (2认同)

Piy*_*iya 31

你可以这样试试.
使用元素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;
            }
      }
Run Code Online (Sandbox Code Playgroud)

现在使用id作为int获取此枚举.

MyEnum myEnum = MyEnum.fromId(5);
Run Code Online (Sandbox Code Playgroud)


oss*_*sys 19

我缓存值并创建一个简单的静态访问方法:

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];
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是我现在使用的解决方案.但是如果你不给字段`values`提供与`values()`方法相同的名字,那么恕我直言.我使用`cachedValues`作为字段名称. (4认同)
  • 高效优雅; 复制并粘贴到我的项目中:)我唯一改变的是fromInt(int i),我刚从(int i)调用它,因为在签名中有两次int是有点多余的. (2认同)

Cam*_*ner 9

Java枚举不具有与它们在C++中执行的相同类型的枚举到int映射.

也就是说,所有枚举都有一个values方法返回一个可能的枚举值数组,所以

MyEnum enumValue = MyEnum.values()[x];
Run Code Online (Sandbox Code Playgroud)

应该管用.这有点令人讨厌,如果可能的话,最好不要尝试从ints 转换为Enums(反之亦然).

  • 但它只有在我的枚举值从0开始时才有效吗? (4认同)

Dil*_*nga 9

这不是通常做的事情,所以我会重新考虑.但话说回来,基本操作是:int - > enum使用EnumType.values()[intNum],枚举 - > int使用enumInst.ordinal().

但是,由于values()的任何实现别无选择,只能为您提供数组的副本(java数组永远不会是只读的),因此使用EnumMap缓存枚举 - > int映射会更好.

  • Re"这不是通常做的事情":有用的常见情况:enum对应于存储在数据库中的int值. (2认同)

w.d*_*hue 7

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

  • 但它只有在我的枚举值从0开始时才有效吗? (4认同)

小智 6

这是我计划采用的解决方案.这不仅适用于非顺序整数,而且它可以与您可能希望用作枚举值的基础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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我只需要在特定时间将id转换为枚举(从文件加载数据时),因此我没有理由始终将Map保留在内存中.如果确实需要始终可以访问地图,则可以始终将其缓存为Enum类的静态成员.


Cha*_*fus 6

如果它有助于其他人,我喜欢的选项(这里没有列出)使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用您可以使用的默认值null,您可以throw IllegalArgumentException或者您fromInt可以返回Optional,无论您喜欢什么行为.

  • 你应该提到你正在使用番石榴.或者你可以使用流:`Map <Integer,MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum :: getValue,Function.identity()));` (3认同)

Yuk*_*oue 5

根据@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());
    }
}
Run Code Online (Sandbox Code Playgroud)