Answers:
要将序数转换为其枚举形式,您可能需要执行以下操作:
ReportTypeEnum value = ReportTypeEnum.values()[ordinal];
请注意数组边界。
请注意,每次调用都会values()
返回一个新克隆的数组,这可能会对性能产生负面影响。如果要经常调用该数组,则可能需要对其进行缓存。
编辑了该答案,以包括评论中给出的反馈
这几乎肯定是一个坏主意。当然,如果序号事实上仍然存在(例如,由于某人已将URL标记为书签),则意味着您enum
将来必须始终保留该顺序,这对于编写代码的维护人员而言可能并不明显。
为什么不编码enum
使用myEnumValue.name()
(并通过解码ReportTypeEnum.valueOf(s)
)呢?
value
在开头或其正确的字母/逻辑位置加上a的可能性要小得多。(从逻辑TimeUnit
如果我要经常使用values()
:
enum Suit {
Hearts, Diamonds, Spades, Clubs;
public static final Suit values[] = values();
}
同时在任何地方.java:
Suit suit = Suit.values[ordinal];
注意数组边界。
Suit.values[0] = Suit.Diamonds;
代码中的某处。理想情况下,这永远不会发生,但是不公开可变字段的总体原则仍然成立。对于这种方法,请考虑使用Collections.unmodifiableList
或类似方法。
Suit values[]
直接或间接(如何提到getValues()
),我使用一种公共方法来解决,在该方法中ordinal
必须以参数的形式发送值并Suit
从中返回表示形式Suit values[]
。这里的要点(从一开始的问题开始就是根据枚举序数创建枚举类型的)
我同意大多数人的观点,即使用序数可能不是一个好主意。我通常通过为枚举提供一个私有构造函数来解决此问题,该私有构造函数可以采用例如DB值,然后创建fromDbValue
类似于Jan的答案的静态函数。
public enum ReportTypeEnum {
R1(1),
R2(2),
R3(3),
R4(4),
R5(5),
R6(6),
R7(7),
R8(8);
private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);
private static Map<Integer, ReportTypeEnum> lookup;
private Integer dbValue;
private ReportTypeEnum(Integer dbValue) {
this.dbValue = dbValue;
}
static {
try {
ReportTypeEnum[] vals = ReportTypeEnum.values();
lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);
for (ReportTypeEnum rpt: vals)
lookup.put(rpt.getDbValue(), rpt);
}
catch (Exception e) {
// Careful, if any exception is thrown out of a static block, the class
// won't be initialized
log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
}
}
public static ReportTypeEnum fromDbValue(Integer dbValue) {
return lookup.get(dbValue);
}
public Integer getDbValue() {
return this.dbValue;
}
}
现在,您可以更改顺序而无需更改查找,反之亦然。
您可以使用静态查找表:
public enum Suit {
spades, hearts, diamonds, clubs;
private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();
static{
int ordinal = 0;
for (Suit suit : EnumSet.allOf(Suit.class)) {
lookup.put(ordinal, suit);
ordinal+= 1;
}
}
public Suit fromOrdinal(int ordinal) {
return lookup.get(ordinal);
}
}
0...(n-1)
,则数组的代码更少,可读性也更高;性能提升只是一个奖励。private static final Suit[] VALUES = values();
和public Suit fromOrdinal(int ordinal) { return VALUES[ordinal]; }
。额外的优势:在无效序号上立即崩溃,而不是无提示地返回null。(并不总是有优势。但是经常如此。)
这就是我用的。我不假装它比上面的简单解决方案“效率”低得多。当上面的解决方案中使用无效序数值时,它的作用是提供比“ ArrayIndexOutOfBounds”更清晰的异常消息。
它利用了EnumSet javadoc指定迭代器以其自然顺序返回元素的事实。如果这是不正确的,则有一个断言。
JUnit4测试演示了如何使用它。
/**
* 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);
}
这是我在带有Proguard的Android上执行的操作:
public enum SomeStatus {
UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order
private static SomeStatus[] values = null;
public static SomeStatus fromInteger(int i) {
if(SomeStatus.values == null) {
SomeStatus.values = SomeStatus.values();
}
if (i < 0) return SomeStatus.values[0];
if (i >= SomeStatus.values.length) return SomeStatus.values[0];
return SomeStatus.values[i];
}
}
它很短,我不必担心在Proguard中出现异常
public enum Suit implements java.io.Serializable, Comparable<Suit>{
spades, hearts, diamonds, clubs;
private static final Suit [] lookup = Suit.values();
public Suit fromOrdinal(int ordinal) {
if(ordinal< 1 || ordinal> 3) return null;
return lookup[value-1];
}
}
测试班
public class MainTest {
public static void main(String[] args) {
Suit d3 = Suit.diamonds;
Suit d3Test = Suit.fromOrdinal(2);
if(d3.equals(d3Test)){
System.out.println("Susses");
}else System.out.println("Fails");
}
}
如果您拥有更高效的代码,我感谢您与我们分享。我的枚举非常庞大,并且经常被调用数千次。
因此,一种方法是ExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal];
可行且容易实现,但是,如前所述,ExampleEnum.values()
每次调用都会返回一个新的克隆数组。那可能是不必要的昂贵。我们可以这样缓存数组来解决ExampleEnum[] values = values()
。允许修改我们的缓存数组也是“危险的”。有人可以写,ExampleEnum.values[0] = ExampleEnum.type2;
所以我将使用不做额外复制的访问器方法将其设为私有。
private enum ExampleEnum{
type0, type1, type2, type3;
private static final ExampleEnum[] values = values();
public static ExampleEnum value(int ord) {
return values[ord];
}
}
您将ExampleEnum.value(ordinal)
用来获取与ordinal
每个枚举都有name(),它给出一个带有枚举成员名称的字符串。
给定enum Suit{Heart, Spade, Club, Diamond}
,Suit.Heart.name()
会给Heart
。
每个枚举都有一个valueOf()
方法,该方法采用枚举类型和字符串来执行相反的操作:
Enum.valueOf(Suit.class, "Heart")
返回Suit.Heart
。
为什么有人会使用普通话,这超出了我的范围。如果枚举成员更改,它可能快十亿分之一秒,但并不安全,因为另一个开发人员可能不知道某些代码依赖于序数值(尤其是在问题中引用的JSP页面中,网络和数据库开销完全支配了时间,而不是在字符串上使用整数)。