【问题标题】:Can I assume that Java enumerations auto-increment by 1?我可以假设 Java 枚举自动递增 1 吗?
【发布时间】:2012-03-26 00:14:50
【问题描述】:

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 语句或条件:

switch (direction) {
    case LEFT:newdirection = Direction.UP;
    break;
  etc...
}

使用序数有几个好处:

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

你怎么看?

【问题讨论】:

  • 如果它很重要(例如,对于自定义序列化),无论如何你最好使用显式映射。只需创建一个EnumMap<Direction, Integer> 或给Direction 一个int 字段。
  • 我宁愿保持干净。这是给学校的,但从技术上讲,我们还没有使用枚举,而且 EnumMap 可能有点极端,因为我们甚至还没有了解数组:D。
  • 您的清洁概念有点误导:-)。依赖序数将是一种非常混乱的编码方式。
  • 我不明白你为什么不依赖比较枚举本身。你到底在用这个做什么?
  • 我的干净概念是“短而清晰”。在每种情况下都有多个条件的 switch 语句不如 2 行代码那么干净。代码更难理解,但更干净。因此,如果您在房间里扔一堆东西,那会很乱。如果你只往里面扔两件小东西,它还是很干净的。

标签: java enumeration ordinal


【解决方案1】:

是的 - 见javadoc

返回此枚举常量的序号(它在其枚举声明中的位置,其中初始常量的序号为零)。

【讨论】:

  • 我不明白:这只是说明初始常数的序数为零,而不是第二个常数的序数为 1,或者第三个常数的序数为 2,...
  • @Korion "它在枚举声明中的位置",从 0 开始。所以 MONDAY.ordinal() == 0,TUESDAY.ordinal() == 1 等等。
  • 对,我的错。非常感谢!
【解决方案2】:

是的 - 但你的代码不应该依赖它,因为当有人插入 Caturday 时它会中断。

【讨论】:

  • 是的,但在我的情况下,枚举将始终保持不变。
  • 你是对的:D。我的枚举实际上是 {UP,RIGHT,DOWN,LEFT} 但我想从技术上讲老师可能会打扰我并添加像 DOWN_LEFT、UP_RIGHT、...这样的方向
  • 我希望你的老师能做到。这将是一个很好的学习课程:)
【解决方案3】:

是的,但是,依赖它会使您的代码变得脆弱。如果你改变枚举中常量的顺序或在它们之间添加常量,一些常量的序数将会改变。因此,例如将序数存储在数据库或文件中并不是一个好主意,因为如果您的源代码发生更改,数据库或文件中的数据将不再与您更改的代码兼容。

更强大的解决方案是使用每个常量显式存储代码。例如:

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);
    }
}

【讨论】:

    【解决方案4】:

    你也可以像这样强制索引:

    enum Direction {
      MONDAY(1),
      TUESDAY(2);
      // etc...
    
      private int value;    
    
      private Direction(int value) {
        this.value = value;
      }
    
      public int getValue() {
        return value;
      }
    }
    

    【讨论】:

      【解决方案5】:

      是的。但是,如果您想在不同的地方重新排序或添加新的枚举,或者如果您找到更改现有值的理由,那么依赖它并不是最好的主意。我发现除了它们的序数值和名称之外,给它们一个实际的值/含义会更好。

      【讨论】:

      • 好的,谢谢您的回答。由于我使用的是像上面这样的标准枚举,它永远不会改变它的内容,我想我会做出假设。
      【解决方案6】:

      序数的问题在于它们取决于枚举值的声明顺序。如果在某个时候一个新值被添加到枚举中,并且它被添加到其他枚举的中间,那么序数将会改变,从而使所有依赖于特定序数值的代码无效。

      如果您绝对必须为序数值分配一个固定数字,这可能会有用:

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

      在上面的 sn-p 中,code 属性与每个枚举值相关联,您可以确定它始终具有相同的值——在构造函数中传递的那个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-07-17
        • 1970-01-01
        • 2012-07-12
        • 1970-01-01
        • 2014-02-21
        • 1970-01-01
        • 2010-09-22
        • 1970-01-01
        相关资源
        最近更新 更多