我可以为Java枚举指定序号吗?

82
ordinal() 方法返回一个枚举实例的序号。
我怎样才能为一个枚举设置序号?
7个回答

90

你可以通过改变枚举的顺序来控制序数,但是不能像在 C++ 中那样显式地设置它。其中一种解决方法是为所需的数字在枚举中提供额外的方法:

enum Foo {
  BAR(3),
  BAZ(5);
  private final int val;
  private Foo(int v) { val = v; }
  public int getVal() { return val; }
}
在这种情况下,BAR.ordinal() == 0,但是BAR.getVal() == 3

11
+1,但这并不是一个解决方法。这是期望的行为。序数值被视为实现细节;如果想要分配整数或其他值,那么“枚举是类”就非常适用了... - andersoj
1
据我所知,枚举索引是从零开始的,那么 BAR.ordinal() 不会返回 0 吗? - Maarten Blokker

73
您不能设置它,它始终是常量定义的顺序。请参见Enum.ordinal()文档

返回此枚举常量的序数(其在其枚举声明中的位置,其中初始常量分配为零)。 大多数程序员将不需要使用此方法。 它专为复杂的基于枚举的数据结构(例如EnumSet和EnumMap)而设计。

实际上,您不应该需要它。 如果您想要一些整数属性,请定义一个。

7
如果我能指定枚举的序列,那么在使用JPA与枚举时会更加安全。 - Keating

10

正如被接受的答案指出的那样,你无法设置序号。你能做到的最接近这一点的方法是使用自定义属性

public enum MonthEnum {

    JANUARY(1),
    FEBRUARY(2),
    MARCH(3),
    APRIL(4),
    MAY(5),
    JUNE(6),
    JULY(7),
    AUGUST(8),
    SEPTEMBER(9),
    OCTOBER(10),
    NOVEMBER(11),
    DECEMBER(12);

    MonthEnum(int monthOfYear) {
        this.monthOfYear = monthOfYear;
    }

    private int monthOfYear;

    public int asMonthOfYear() {
        return monthOfYear;
    }

}

注意: 默认情况下,如果您不指定值,枚举 值将从 0 开始(而不是 1)。此外,每个项的值不必递增 1


5
您可以使用反射更新序数:
private void setEnumOrdinal(Enum object, int ordinal) {
    Field field;
    try {
        field = object.getClass().getSuperclass().getDeclaredField("ordinal");
        field.setAccessible(true);
        field.set(object, ordinal);
    } catch (Exception ex) {
        throw new RuntimeException("Can't update enum ordinal: " + ex);
    }
}

2
如果您愿意这样做,最好重新排列枚举字段。这会更容易、更安全、更易读。 - Gili

2

来自http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Enum.html

public final int ordinal()返回此枚举常量的序数(它在其枚举声明中的位置,其中最初的常量被赋予零的序数)。大多数程序员将不会使用此方法。它是为高级基于枚举的数据结构设计的,例如EnumSet和EnumMap。

返回值:此枚举常量的序数

如果你有

public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }

那么SUNDAY的序数为0,MONDAY为1,以此类推...


3
ortinal不能保证给出上述排序顺序! - claj
1
@claj,你能详细解释一下吗?文档似乎表明它确实可以。 - Celos
抱歉@Celos,第一个枚举确实是0,但规范中没有提到该值应该如何分配,除了单调递增之外。我想我在《Effective Java》中读到过这个注意事项之类的内容,但不要只听我的意见。 - claj

0

查看Java 枚举示例文档

返回此枚举常量的序数(它在其枚举声明中的位置,其中初始常量被分配为零)。大多数程序员不会使用此方法。它是为复杂的基于枚举的数据结构(例如EnumSet和EnumMap)设计的。


-6
简单的答案是:只需更改常量的顺序。第一个定义的将是0,第二个将是1,以此类推。但是,如果您的代码经常变化或枚举具有许多值,则可能不实用。您可以定义一个自定义方法来解决默认序数的问题,但一定要确保它有良好的文档记录,以避免混淆!
public enum Values
{
    ONE, TWO, THREE, FOUR;

    public int getCustomOrdinal()
    {
        if(this == ONE)
        {
            return 3;
        }
        else if(this == TWO)
        {
            return 0;
        }
        ...
    }
}

4
使用switch语句可能比一系列的if-else语句更好。 - Peter Lawrey
6
我不喜欢这种解决方案。Enums 是类,因此可以包含自定义属性。我更愿意为此正确地定义一个字段和一个相应的 getter 方法。 - Atmocreations
一般来说,那是更好的解决方案。但问题是询问是否可以改变ordinal()的行为... - donnyton
2
为什么不直接声明一个属性"customOrdinal",然后将枚举常量初始化为ONE(3)TWO(0)等,以消除任何if/else或switch语句? - techfly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接