在 Java 中对枚举使用 = = 可以吗?

对 Java 中的枚举使用 ==可以吗,还是需要使用 .equals()?在我的测试中,==总是有效的,但是我不确定我是否能保证这一点。特别是,枚举上没有 .clone()方法,所以我不知道是否有可能获得一个枚举,对于这个枚举,.equals()将返回与 ==不同的值。

例如,这样可以吗:

public int round(RoundingMode roundingMode) {
if(roundingMode == RoundingMode.HALF_UP) {
//do something
} else if (roundingMode == RoundingMode.HALF_EVEN) {
//do something
}
//etc
}

或者我需要这样写:

public int round(RoundingMode roundingMode) {
if(roundingMode.equals(RoundingMode.HALF_UP)) {
//do something
} else if (roundingMode.equals(RoundingMode.HALF_EVEN)) {
//do something
}
//etc
}
46200 次浏览

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

However, there's a better way of writing your round method:

public int round(RoundingMode roundingMode) {
switch (roundingMode) {
case HALF_UP:
//do something
break;
case HALF_EVEN:
//do something
break;
// etc
}
}

一种甚至是 好多了的方法是将功能放在枚举本身中,因此您可以直接调用 roundingMode.round(someValue)。这涉及到 Java 枚举的核心——它们是 面向对象枚举,与其他地方发现的“命名值”不同。

EDIT: The spec isn't very clear, but 第8.9条 states:

枚举类型的主体可能包含 枚举常数 defines an instance of the enum type. 枚举类型没有其他实例 而不是它的枚举定义的那些 常数。

= = 比较两个对象的引用。对于枚举,它保证只有一个实例,因此对于任何两个相同的枚举,= = 将为 true。

参考文献:

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

(在 Sun 的文档中找不到任何东西)

这是 Sun 发布的 Enum.java 代码和 JDK 的一部分:

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




}

下面是一些你可能会感兴趣的邪恶代码

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

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

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

However, the enum construct gives you various benefits:

  • 每个实例的 toString ()打印代码中给出的名称。
  • (正如在另一篇文章中提到的)枚举类型的变量可以使用 switch-case控制结构与常量进行比较。
  • 可以使用为每种枚举类型“生成”的 values字段查询枚举中的所有值
  • 下面是一个重要的 w.r.t 身份比较: 枚举值在序列化过程中不需要克隆。

序列化是个大问题。如果我使用上面的代码而不是枚举,下面是身份相等的表现:

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

您使用一种包含 writeReplacereadResolve的技术(参见 http://java.sun.com/j2se/1.4.2/docs/api/java/io/Serializable.html) ,在不使用枚举的情况下解决这个问题..。

我想要说的是—— Java 特意允许您使用枚举值的标识来测试相等性; 这是一种受到鼓励的做法。

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

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

请注意,通过 RMI/IIOP 传输枚举时存在问题:

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

= = 一般来说是可以的,而且 = = 和 .equals()都有优点。我个人更喜欢在比较对象时使用 .equals(),包括 enum。请参阅下面的讨论:

比较 Javaenum 成员: = = 还是 equals () ?