使用Enum的序数值来索引Java中的数组是不好的做法吗?

时间:2009-10-15 19:37:30

标签: java enums

我有两个数组:Walls和Neighbors。

public boolean[] walls = new boolean[4];
public Cell[] neighbors = new Cell[4];

我有一个Enum:

enum Dir
{
    North,
    South,
    East,
    West
}

现在,我希望能够按照他们的方向访问墙壁或邻居,所以我不必传递一堆魔法索引。

然而,当我阅读Enum.ordinal()的文档时,它说程序员几乎没有使用这种方法,这让我觉得它不应该以这种方式使用。

我在想做类似的事情:

    List<Dir> availableDirections = new ArrayList<Dir>();
    for(Dir direction : Dir.values())
        if (!Neighbors[direction.ordinal()].Visited)
            availableDirections.add(direction);

甚至:

return Neighbors[Dir.North.ordinal()];

我应该恢复为NORTH,SOUTH,EAST,WEST使用静态常量并为其设置索引值,还是使用Enum的序数方法?

7 个答案:

答案 0 :(得分:16)

在一个切线问题上,为邻居使用EnumMap可能更好:

Map<Dir, Cell> neighbours = 
    Collections.synchronizedMap(new EnumMap<Dir, Cell>(Dir.class));

neighbours.put(Dir.North, new Cell());

for (Map.Entry<Dir, Cell> neighbour : neighbours.entrySet()) {
    if (neighbour.isVisited()) { ... }
}

etc..

BTW:按惯例,枚举实例应全部为大写,

enum Dir {
    NORTH,
    EAST, 
    SOUTH,
    WEST
}

答案 1 :(得分:13)

文档只说大多数程序员对该方法没有用处。这是合法使用的一个案例。 假设您的类控制枚举和数组,没有理由担心ordinal()方法索引数组(因为您始终可以使它们保持同步)。

但是,如果您的使用情况变得更复杂,您可能会想要使用EnumMap,而不是建议使用。

答案 2 :(得分:13)

您还可以增强枚举(顺时针索引):

enum Dir
{
  NORTH(0),
  SOUTH(2),
  EAST(1),
  WEST(3);

  private final int index;

  private Dir(int index) {
    this.index = index;
  }

  public int getIndex() {
    return index;
  }

}

答案 3 :(得分:3)

JavaDoc说

  

大多数程序员都没用   这种方法。它专为使用而设计   复杂的基于枚举的数据   结构,如EnumSet和   EnumMap的。

我认为他们想说大多数程序员更喜欢使用EnumMap或EnumSet而不是手动索引到数组中。它们当然并不意味着你应该用你的枚举替换几个整数变量,因为这样做会失去类型安全性。

如果您需要灵活地能够重新排序枚举常量而不影响数组中的顺序,您可以将索引隔离到枚举的另一个字段中,如Arne所描述的那样。

答案 4 :(得分:2)

如果您没有持久化数组或以任何其他方式使自己依赖于枚举类的不同版本,则使用ordinal()是安全的。

如果您不想依赖枚举值的隐式排序,可以引入私有索引值:

public enum Direction {
  NORTH(0),
  SOUTH(1),
  EAST(2),
  WEST(3);

  private int _index;

  private Direction (int index_)
  {
    _index = index_;
  }

  public int getIndex()
  {
    return _index;
  }
}

从这里开始,两者都很容易查找到Direction的索引(通过在静态块中创建Map以实现紧凑的持久性;在静态块中执行唯一性检查等。

答案 5 :(得分:1)

使用enum的序数取决于隐式顺序。我喜欢明确,特别是如果你使用整数值作为数组的索引,将值链接到意义。

在这种情况下,我会选择使用final static int NORTH = 0

答案 6 :(得分:1)

我强烈建议不要使用它,因为Ordinal值是基于java代码中的顺序。

使用ordinal()会使代码很难维护,特别是如果某种形式的持久性进入等式。

例如,如果您决定添加对角线方向,例如NORTH_WEST,SOUTH_EAST。 如果您使用的是ordinal(),则必须在列表底部添加这些内容,否则以前可能会成为NORTH的内容。

即您可以将您的enyum更改为(可能)更改功能

N  (is now 0 was 0) 
NE (is now 1) 
E (is now 2 was 1) 
SE (is now 3 ) 
S  (is mow 4 was 2) 
SW (is now 5) 
W  (is now 6 was 3)