我可以假设Java枚举自动递增1吗?

7

Java规定初始值的序数为0。我可以假设当我创建一个枚举时,它是这样的:

public enum Direction {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, ...}

星期二TUESDAY的序数始终为1,星期三WEDNESDAY的序数始终为2,...


我会更具体一些。我正在声明一个枚举:

public enum Direction {UP,RIGHT,DOWN,LEFT}

现在有一种方法可以将内容旋转90度(顺时针)。使用序数可以实现一行代码:
direction = Direction.values()[direction.ordinal()+1 % Direction.values().length];

如果我不使用顺序,我将不得不使用开关语句或条件语句:
switch (direction) {
    case LEFT:newdirection = Direction.UP;
    break;
  etc...
}

使用序数有一些优点:

  • 代码更短
  • 代码执行速度更快(可以忽略不计)
  • 如果添加了一个方向(例如DOWN_LEFT),实现不一定需要改变,只需将新方向放在正确的位置即可

您认为呢?


2
如果这很重要(例如用于自定义序列化),最好还是使用显式映射。只需创建一个 EnumMap<Direction, Integer> 或给 Direction 添加一个 int 字段即可。 - Mark Peters
我宁愿保持简洁。虽然这是为了学校,但从技术上讲,我们还没有使用枚举,而EnumMap可能有点过于复杂,因为我们甚至还没有学习数组 :D。 - Fatso
你对“清晰”的概念有些误导人 :-). 依赖序数将是编写此代码的一种极其混乱的方式。 - Mark Peters
我不明白为什么你不直接依赖于比较枚举本身。你具体是用来做什么的? - AHungerArtist
@AHungerArtist:因为这是为学校而做的,而我是一个完美主义者。依赖序数会使我的代码更短更快(虽然只有一毫秒,但仍然是一毫秒)。 - Fatso
显示剩余2条评论
6个回答

8
是的 - 请参考 Java 官方文档中的 javadoc:
返回此枚举常量的序数 (它在枚举声明中的位置,其中初始常量被分配为零的序数)。

我不理解:这只是说明初始常量的序数为零,而不是第二个常量具有序数1,或者第三个常量具有序数2,... - Fatso
@Korion 枚举声明中的位置,从0开始。因此,MONDAY.ordinal() == 0,TUESDAY.ordinal() == 1等等。 - assylias

7
是的,但是您的代码不应该依赖它,因为当有人插入Caturday时,它就会出现问题。

真的,但在我的情况下,枚举将始终保持不变。 - Fatso
你说得对:D。实际上我的枚举是{UP, RIGHT, DOWN, LEFT},但我猜老师在技术上可能会纠缠我,添加像DOWN_LEFT, UP_RIGHT这样的方向... - Fatso
2
希望你的老师会这么做。这将是一个很好的学习教训 :) - AHungerArtist

4

是的,然而,仅依赖此方法会使您的代码变得脆弱。如果您改变枚举常量的顺序或在它们之间添加常量,则某些常量的序数将发生变化。因此,例如,不建议将序数存储在数据库或文件中,因为如果源代码更改,则数据库或文件中的数据将不再与更改后的代码兼容。

更健壮的解决方案是显式地为每个常量存储代码。例如:

public enum Status {
    NEW(0),
    PROCESSING(1),
    OK(2),
    ERROR(99);

    private final int code;

    private Status(int code) {
        this.code = code;
    }

    // Get the code for an enum constant
    public int getCode() {
        return code;
    }

    // Given a code, get the corresponding enum constant
    public static Status fromCode(int code) {
        for (Status s : Status.values()) {
            if (s.code == code) {
                return s;
            }
        }

        throw new IllegalArgumentException("Invalid code: " + code);
    }
}

3
您可以通过以下方式强制索引:
enum Direction {
  MONDAY(1),
  TUESDAY(2);
  // etc...

  private int value;    

  private Direction(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }
}

2

是的。然而,如果您想在不同位置重新排序或添加新的枚举,或者发现需要更改现有值,仅依靠此方法可能并不是最好的选择。我认为最好为它们提供实际的值/含义,而不仅仅是序数值和名称。


好的,谢谢你的回答。由于我正在使用类似上面那样永远不会更改其内容的标准枚举,所以我想我会做出这个假设。 - Fatso

1

枚举类型的序数问题在于它们依赖于枚举值声明的顺序。如果在某个时刻向枚举中添加了一个新值,并且该值添加在其他值的中间,则序数将发生变化,从而使所有依赖于特定序数值的代码失效。

如果您绝对必须为序数值分配固定数字,则可能会有所帮助:

enum Directions {
    NORTH(1),
    SOUTH(2),
    WEST(3),
    EAST(4);
    private int code;
    Directions(int code) {
        this.code = code;
    }
    public int getCode() {
        return code;
    }
}

在上面的代码片段中,每个枚举值都关联了一个“code”属性,并且您可以确信它将始终具有相同的值-即在构造函数中传递的值。

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