关于语法:在Java中的枚举上使用==可以吗?

Is it OK to use == on enums in Java?

在Java中使用EnOCX1 0Ω可以吗?或者我需要使用EDCOX1?1?在我的测试中,==总是有效的,但我不确定是否能保证。特别是,一个枚举没有.clone()方法,所以我不知道是否可以得到一个.equals()将返回与==不同的值的枚举。

例如,是否可以:

1
2
3
4
5
6
7
8
public int round(RoundingMode roundingMode) {
  if(roundingMode == RoundingMode.HALF_UP) {
    //do something
  } else if (roundingMode == RoundingMode.HALF_EVEN) {
    //do something
  }
  //etc
}

或者我需要这样写:

1
2
3
4
5
6
7
8
public int round(RoundingMode roundingMode) {
  if(roundingMode.equals(RoundingMode.HALF_UP)) {
    //do something
  } else if (roundingMode.equals(RoundingMode.HALF_EVEN)) {
    //do something
  }
  //etc
}


就我2分:这是Sun发布的Enum.java代码,也是JDK的一部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class Enum<E extends Enum<E>>
    implements Comparable<E>, Serializable {

    // [...]

    /**
     * Returns true if the specified object is equal to this
     * enum constant.
     *
     * @param other the object to be compared for equality with this object.
     * @return  true if the specified object is equal to this
     *          enum constant.
     */

    public final boolean equals(Object other) {
        return this==other;
    }


}


是的,==很好-保证每个值只有一个引用。

但是,有一种更好的方法可以编写您的圆形方法:

1
2
3
4
5
6
7
8
9
10
11
public int round(RoundingMode roundingMode) {
  switch (roundingMode) {
    case HALF_UP:
       //do something
       break;
    case HALF_EVEN:
       //do something
       break;
    // etc
  }
}

更好的方法是将功能放在枚举本身中,这样您就可以调用roundingMode.round(someValue)。这涉及到Java枚举的核心——它们是面向对象的枚举,不同于在别处发现的"命名值"。

编辑:规格不是很清楚,但第8.9节规定:

The body of an enum type may contain
enum constants. An enum constant
defines an instance of the enum type.
An enum type has no instances other
than those defined by its enum
constants.


是的,就好像您已经为枚举中的每个值创建了单例实例:

1
2
3
4
5
6
7
8
public abstract class RoundingMode {
  public static final RoundingMode HALF_UP = new RoundingMode();
  public static final RoundingMode HALF_EVEN = new RoundingMode();

  private RoundingMode() {
    // private scope prevents any subtypes outside of this class
  }
}

但是,enum结构为您提供了各种好处:

  • 每个实例的toString()打印代码中给定的名称。
  • (如另一篇文章所述)可以使用switch-case控制结构将枚举类型的变量与常量进行比较。
  • 可以使用为每个枚举类型"生成"的values字段查询枚举中的所有值。
  • 下面是一个重要的W.R.T身份比较:枚举值可以在不进行克隆的情况下进行序列化。

系列化是一个很大的哥特式风格。如果我使用上面的代码而不是枚举,那么身份平等将如何表现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RoundingMode original = RoundingMode.HALF_UP;
assert (RoundingMode.HALF_UP == original); // passes

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(original);
oos.flush();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
RoundingMode deserialized = (RoundingMode) ois.readObject();

assert (RoundingMode.HALF_UP == deserialized); // fails
assert (RoundingMode.HALF_EVEN == deserialized); // fails

您可以使用EDCOX1 4和EDCOX1 5的技术来解决这个问题,不需要枚举,(参见http://java.

我想关键是——Java不允许你使用EnUM值的身份来测试相等性,这是一种鼓励的做法。


==比较两个对象的引用。对于枚举,可以保证只有一个实例,因此对于任何两个相同的枚举,==都是真的。

参考文献:

http://www.ajaxonomy.com/2007/java/making-the-most-of-java-50-enum-tricks

(在Sun文档中找不到任何内容)


这里有一些你可能会觉得有趣的邪恶代码。D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public enum YesNo {YES, NO}

public static void main(String... args) throws Exception {
    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    Unsafe unsafe = (Unsafe) field.get(null);
    YesNo yesNo = (YesNo) unsafe.allocateInstance(YesNo.class);

    Field name = Enum.class.getDeclaredField("name");
    name.setAccessible(true);
    name.set(yesNo,"YES");

    Field ordinal = Enum.class.getDeclaredField("ordinal");
    ordinal.setAccessible(true);
    ordinal.set(yesNo, 0);

    System.out.println("yesNo" + yesNo);
    System.out.println("YesNo.YES.name().equals(yesNo.name())"+YesNo.YES.name().equals(yesNo.name()));
    System.out.println("YesNo.YES.ordinal() == yesNo.ordinal()"+(YesNo.YES.ordinal() == yesNo.ordinal()));
    System.out.println("YesNo.YES.equals(yesNo)"+YesNo.YES.equals(yesNo));
    System.out.println("YesNo.YES == yesNo" + (YesNo.YES == yesNo));
}


枚举是阻塞多态代码的好地方。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Rounding {
  ROUND_UP {
    public int round(double n) { ...; }
  },
  ROUND_DOWN {
    public int round(double n) { ...; }
  };

  public abstract int round(double n);
}

int foo(Rounding roundMethod) {
  return roundMethod.round(someCalculation());
}

int bar() {
  return foo(Rounding.ROUND_UP);
}


==一般都可以,而且对==和.equals()都有好处。我个人喜欢在比较对象时总是使用.equals(),包括enums。另请参见本讨论:

比较JavaEnm成员:= =或均衡器()?


请注意,通过rmi/iiop传输枚举时出现问题。查看此线程:

http://www.velocityreviews.com/forums/t390342-enum-equality.html