枚举 vs. 类加载器

9
有时候您可能并不知道您的代码所在的环境中有多个类加载器。即使在这种情况下,我还能期望"=="操作符可以用于枚举值吗?
3个回答

13

只要枚举类型只通过一个类加载器可用,多个类加载器可能不是问题。如果不是这种情况,您将失去枚举类型的所有好处。

另外,使用equals()也无法解决问题。以下是Java 1.6中Enum.equals(Object)的实现:

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

和josefx的帖子一样,当枚举被多个类加载器加载时仍然可以工作,只需要小心确保它们相互隔离即可。 - Mark Peters
当然可以,但这很麻烦。它会打破人们对枚举的任何假设,并且会破坏枚举单例模式。 - Sean Patrick Floyd
6
类加载器破坏了所有单例模式。 - josefx

10

如果你的枚举类只被加载一次,它仍然可以工作。

  • 你的枚举类只在已加载的插件中使用
  • 该枚举类已经被单个插件类加载器的父类加载器加载了

如果你的枚举类被不同的类加载器加载,它将无法工作

  • 你在不同的插件之间传递枚举值,但应用程序类加载器没有加载这个枚举类。(如果枚举值从未跨越插件,则仍然可以工作)

为什么会出现这种情况

Java使用对象实例来表示不同的枚举值,每个实例都存储在枚举类中的静态字段中。如果枚举被加载两次,每个枚举值由两个不同的对象实例表示。 ==操作符 只比较引用,并不知道代表枚举值的多个实例,因此无法匹配由不同类加载器加载的值。


"== 运算符仅比较引用"听起来有点像教条。枚举已经是一件相当特殊的事情了。再定义一个特殊性质,例如将 "==" 定义为 "this.ordinal() == that.ordinal()",这样能解决问题吗? - Dima
只要枚举的两个加载定义相同,它就可以工作。序数值仅包含源代码中Enum常量的索引(位置),如果代码更改(新值,不同的排序),它仍将中断。如果速度不是问题,您可以比较它们的名称。 - josefx

-5

"==" 不会起作用,但你仍然想使用 .equals()

你可能会对 Apache Commons Lang 类感兴趣:链接文本


1
顺便提一下,枚举类型的 equals() 实现只是调用了 this==other (Sun/Oracle JDK 6)。 - Grzegorz Oledzki
是的,正如我在自己的答案中所写的。 - Sean Patrick Floyd
这可能适用于此版本。然而,根据语言语义,== 永远不会有效,而 .equals() 可能(!)有效。请参见 apache-commons 枚举实现。 - b_erb
1
我知道“==”和“equals()”之间的重要区别。但是枚举类型有意违反了这个区别,而且这种情况不太可能改变。虽然从语义上讲,“equals”是更好的选择。 - Sean Patrick Floyd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接