给定以下枚举,将Int强制转换为Java中的枚举的正确方法是什么?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
给定以下枚举,将Int强制转换为Java中的枚举的正确方法是什么?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Answers:
尝试MyEnum.values()[x]
在x
必须为0
or的地方1
,即该枚举的有效序数。
请注意,在Java中,枚举实际上是类(因此,枚举值是对象),因此无法将an 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()
每次都会生成一个新数组,因为数组是可变的,因此多次返回相同数组并不安全。switch语句不一定是O(n),它们可以编译为跳转表。因此,洛伦佐的主张似乎是合理的。
myEnum = myEnumValues[i]
则仍将返回枚举中的i
第e个项目,而无需进行任何更改。
如果要提供整数值,则可以使用以下结构
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
提供与方法相同的名称,它将减少混乱values()
。我使用cachedValues
字段名称。
Java枚举没有在C ++中进行的那种枚举到整数的映射。
也就是说,所有枚举都有一个values
返回可能的枚举值数组的方法,因此
MyEnum enumValue = MyEnum.values()[x];
应该管用。有点讨厌,最好不要尝试将int
s 转换为Enum
s(反之亦然)。
这不是通常要做的事情,所以我会重新考虑。但是,基本的操作是:int->使用EnumType.values()[intNum]的枚举,以及enum->使用enumInst.ordinal()的int。
但是,由于values()的任何实现都别无选择,只能给您一个数组的副本(java数组绝不是只读的),因此最好使用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转换为枚举,所以没有理由让我始终将Map保留在内存中。如果确实需要始终可访问该映射,则可以始终将其作为Enum类的静态成员进行缓存。
clearCachedValues
(将私有字段设置为null)。我认为MyEnum.fromInt(i)
比绕过地图对象更容易理解。
为了帮助其他人,我更喜欢的选项(未在此处列出)使用了Guava的Maps功能:
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()
到静态数组中。
这是与医生相同的答案,但它显示了如何消除可变数组的问题。如果您首先由于分支预测而使用这种方法,则效果几乎没有到零,并且整个代码仅调用一次可变数组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;
}
}