/**
* convert ordinal to Enum
* @param clzz may not be null
* @param ordinal
* @return e with e.ordinal( ) == ordinal
* @throws IllegalArgumentException if ordinal out of range
*/
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
EnumSet<E> set = EnumSet.allOf(clzz);
if (ordinal < set.size()) {
Iterator<E> iter = set.iterator();
for (int i = 0; i < ordinal; i++) {
iter.next();
}
E rval = iter.next();
assert(rval.ordinal() == ordinal);
return rval;
}
throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}
@Test
public void lookupTest( ) {
java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
System.out.println(tu);
}
9 回答
要将序数转换为其枚举represantation,您可能希望这样做:
请注意数组边界 .
请注意,每次调用
values()
都会返回一个新克隆的数组,这可能会以负面方式影响性能 . 如果要经常调用它,您可能希望缓存该数组 .Code example on how to cache values() .
编辑此答案以包括评论中给出的反馈
这几乎肯定是 a bad idea . 当然,如果序数被事实上持久化(例如因为某人已经为URL添加了书签) - 这意味着您将来必须始终保留
enum
顺序,这对于维护人员的编码可能并不明显 .为什么不使用
myEnumValue.name()
(并通过ReportTypeEnum.valueOf(s)
解码)编码enum
?如果我将要使用
values()
:同时wherever.java:
注意阵列界限 .
您可以使用静态查找表:
我同意大多数人使用序数可能是一个坏主意 . 我通常通过给枚举一个私有构造函数来解决这个问题,该构造函数可以采用例如DB值,然后创建一个类似于Jan答案中的静态
fromDbValue
函数 .现在您可以在不更改查找的情况下更改顺序,反之亦然 .
这就是我使用的 . 我并没有假装它比上面简单的解决方案更“有效” . 当在上面的解决方案中使用无效的序数值时,它所做的是提供比“ArrayIndexOutOfBounds”更清晰的异常消息 .
它利用了EnumSet javadoc指定迭代器以其自然顺序返回元素的事实 . 如果这不正确,就会有一个断言 .
JUnit4测试演示了它是如何使用的 .
考试班
如果你有更高效的代码,我很感激你与我们分享,我的枚举是巨大的,不断被召唤数千次 .
这就是我在Android上用Proguard做的事情:
它很短,我不需要担心在Proguard中有例外
每个枚举都有name(),它给出一个名为enum成员的字符串 .
鉴于
enum Suit{Heart, Spade, Club, Diamond}
,Suit.Heart.name()
将给出Heart
.每个枚举都有一个
valueOf()
方法,它采用枚举类型和字符串来执行反向操作:Enum.valueOf(Suit.class, "Heart")
返回Suit.Heart
.为什么有人会使用序数超出我的范围 . 它可能要快几纳秒,但是如果枚举成员发生变化则不安全,因为另一个开发人员可能不知道某些代码依赖于序数值(特别是在问题中引用的JSP页面中,网络和数据库开销完全占主导地位)时间,不使用字符串上的整数) .