65

假设我有一个枚举:

enum E {
    A, B, C;
}

lucasmo的这个答案所示,枚举值按照初始化的顺序存储在静态数组中,您以后可以使用.E.values()

现在假设我想实现E#getNext并且E#getPrevious使得以下所有表达式都计算为true

E.A.getNext() == E.B
E.B.getNext() == E.C
E.C.getNext() == E.A

E.A.getPrevious() == E.C
E.B.getPrevious() == E.A
E.C.getPrevious() == E.B

我目前的实现getNext如下:

public E getNext() {
    E[] e = E.values();
    int i = 0;
    for (; e[i] != this; i++)
        ;
    i++;
    i %= e.length;
    return e[i];
}

和类似的方法getPrevious

然而,这段代码充其量似乎很麻烦(例如,“空”for循环,有争议的计数器变量滥用,最坏的情况可能是错误的(可能是思考反射)。

在 Java 7 中实现枚举类型的最佳方法getNext和方法是什么?getPrevious


注意:我不希望这个问题是主观的。我对“最佳”实现的要求是要求最快、最干净和最可维护的实现的简写。

4

4 回答 4

101

试试这个:

public static enum A { 
    X, Y, Z;
    private static A[] vals = values();
    public A next()
    {
        return vals[(this.ordinal()+1) % vals.length];
    }

的实现留作previous()练习,但回想一下,在 Java 中,模a % b可以返回一个负数

编辑:按照建议,制作数组的私有静态副本values()以避免每次next()previous()调用数组复制。

于 2013-06-09T03:57:56.103 回答
7

或者,可以以某种方式遵循以下想法:

public enum SomeEnum {
  A, B, C;

  public Optional<SomeEnum> next() {
    switch (this) {
      case A: return Optional.of(B);
      case B: return Optional.of(C);
      // any other case can NOT be mapped!
      default: return Optional.empty();
  }
}

笔记:

  1. 与其他答案相比,这种方式进行了一些隐式映射;而不是依靠ordinal(). 当然这意味着更多的代码;但这也迫使作者考虑添加新常量或删除现有常量意味着什么。依赖序数时,您的隐含假设是该顺序基于用于枚举常量声明的顺序。因此,当有人在 6 个月后回来并且必须添加一个新常量时,他必须了解新常量 Y 需要X, Y, Z......而不是仅仅追加X, Z, Y
  2. 在某些情况下,“最后一个”枚举常量将“第一个”作为继任者没有任何意义。以 T 恤尺寸为例。XXL.next() 肯定不是 XS。对于这种情况,使用 Optional 是更合适的答案。
于 2017-01-03T13:04:47.287 回答
1
public enum Three
{
    One, Two, Three;

    static 
    public final Three[] values = values();

    public Three prev() {
        return values[(ordinal() - 1  + values.length) % values.length];
    }

    public Three next() {
        return values[(ordinal() + 1) % values.length];
    }
}
于 2020-05-19T16:21:32.677 回答
0

这不允许环绕,但您可以将其用作检查邻接的低影响方式:

enum Phase {
    ONE, TWO, THREE;
    public final Phase previous;
    Phase() {
        previous = Data.last;
        Data.last = this
    }
    private static class Data {
        private static Phase last = null;
    }
}

class Example {
    Phase currentPhase = Phase.ONE;

    void advanceToPhase(Phase nextPhase) {
        if (nextPhase.previous == currentPhase)
            currentPhase = nextPhase;
    }
}

它必须使用辅助静态类来存储静态初始化器的变量,但它的优点是启动时成本极低。

于 2021-12-28T05:38:22.177 回答