我知道Java枚举被编译为具有私有构造函数和一堆公共静态成员的类.当比较给定枚举的两个成员时,我总是使用.equals(),例如
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
但是,我刚刚遇到一些使用equals运算符==而不是.equals()的代码:
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
我应该使用哪个运营商?
Rev*_*nzo 1485
两者在技术上都是正确的.如果你查看源代码.equals(),它只是按照==.
==但是,我使用它,因为它将是null安全的.
pol*_*nts 1067
==用enum吗?是:枚举具有严格的实例控件,允许您==用于比较实例.这是语言规范提供的保证(由我强调):
JLS 8.9枚举
枚举类型没有除其枚举常量定义的实例之外的实例.
尝试显式实例化枚举类型是编译时错误.该
final clone方法Enum确保enum永远不会克隆常量,并且序列化机制的特殊处理确保不会因反序列化而创建重复实例.禁止对枚举类型进行反射实例化.总之,这四件事确保enum除了enum常量定义的类型之外不存在任何类型的实例.因为只有一个每个实例
enum常数,它允许使用的==操作者代替的equals比较两个对象的引用时,如果已知它们中的至少一个是指方法enum常数.(equals方法inEnum是一种final仅调用super.equals其参数并返回结果的方法,从而执行身份比较.)
这种保证足够强大,Josh Bloch建议,如果你坚持使用单例模式,实现它的最好方法是使用单个元素enum(参见:Effective Java 2nd Edition,Item 3:使用单元素强制执行单例属性)私有构造函数或枚举类型 ;还有Singleton中的线程安全性)
==和之间有什么区别equals?提醒一下,一般来说,==它不是一个可行的替代方案equals.但是,如果是(例如enum),则需要考虑两个重要的差异:
== 永远不会抛出 NullPointerExceptionenum Color { BLACK, WHITE };
Color nothing = null;
if (nothing == Color.BLACK); // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException
Run Code Online (Sandbox Code Playgroud)
== 在编译时受类型兼容性检查的影响enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };
if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT); // DOESN'T COMPILE!!! Incompatible types!
Run Code Online (Sandbox Code Playgroud)
==适用时应该使用?Bloch特别提到,对其实例进行适当控制的不可变类可以保证其客户端==可用.enum具体提到举例说明.
第1项:考虑静态工厂方法而不是构造函数
[...]它允许不可变类保证不存在两个相等的实例:
a.equals(b)if和only ifa==b.如果一个类提供了这种保证,那么它的客户端可以使用==运算符而不是equals(Object)方法,这可以提高性能.枚举类型提供此保证.
总之,使用参数==上enum有:
Pas*_*ent 84
使用==比较两个枚举值的作品,因为只有一个每个枚举常量对象.
另外,==如果您这样编写,则实际上不需要使用写入null安全代码equals():
public useEnums(final SomeEnum a) {
if (SomeEnum.SOME_ENUM_VALUE.equals(a)) {
…
}
…
}
Run Code Online (Sandbox Code Playgroud)
这是一种称为" 从左边比较常数"的最佳实践,你绝对应该遵循.
Tob*_*ias 58
正如其他人所说,无论是==和.equals()工作在大多数情况下.编译时确定你没有比较其他人指出的完全不同类型的对象是有效和有益的,但是FindBugs也可以找到比较两种不同编译时类型的对象的特定类型的错误(并且可能由Eclipse/IntelliJ编译时检查),因此Java编译器发现它并没有增加那么多额外的安全性.
然而:
==不会抛出NPE在我心目中是一个不利的==.几乎不需要enum类型null,因为您可能希望表达的任何额外状态null可以enum作为附加实例添加到其中.如果出乎意料的话null,我宁愿拥有NPE而不是==默默地评估为假.因此,我不同意它在运行时意见更安全 ; 养成永远不让enum价值观念的习惯更好@Nullable.==是快也是伪造的.在大多数情况下,你会打电话给.equals()在其编译时间类型是枚举类变量,并在这些情况下,编译器可以知道,这是一样的==(因为enum的equals()方法不能被覆盖),并可以优化函数调用远.我不确定编译器当前是否这样做,但如果它没有,并且结果证明是整体Java中的性能问题,那么我宁愿修复编译器而不是让100,000个Java程序员改变他们的编程风格以适应特定编译器版本的性能特征.enums是对象.对于所有其他对象类型,标准比较.equals()不是==.我认为做一个例外是很危险的,enums因为你最终可能会意外地比较对象==而不是equals(),特别是如果你enum将一个重构为一个非枚举类.在这种重构的情况下,从上面的工作点是错误的.为了说服自己使用==是正确的,你需要检查有问题的值是一个enum还是一个原始的; 如果它是一个非enum类,它是错的,但容易错过,因为代码仍然可以编译.使用.equals()错误的唯一情况是所讨论的值是原始值; 在这种情况下,代码将无法编译,因此更难以错过.因此,.equals()更容易识别正确,并且对未来的重构更安全.我实际上认为Java语言应该在对象上定义==以在左侧值上调用.equals(),并为对象标识引入单独的运算符,但这不是Java的定义方式.
综上所述,笔者仍然认为论点赞成使用.equals()的enum类型.
Pau*_*Pau 15
我更喜欢使用==而不是equals:
其他原因,除了这里已经讨论过的其他原因之外,你可能会在没有意识到的情况下引入一个bug.假设你有这个枚举完全相同但是在分开的pacakges中(这不常见,但可能会发生):
第一个枚举:
package first.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
Run Code Online (Sandbox Code Playgroud)
第二个枚举:
package second.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
Run Code Online (Sandbox Code Playgroud)
然后,假设你使用等号就像在接下来的item.category这是first.pckg.Category,但你导入第二枚举(second.pckg.Category),而不是第一个没有意识到这一点:
import second.pckg.Category;
...
Category.JAZZ.equals(item.getCategory())
Run Code Online (Sandbox Code Playgroud)
所以你会得到false一个不同的枚举,虽然你期望是真的,因为item.getCategory()是JAZZ.它可能有点难以看到.
因此,如果您改为使用运算符==,则会出现编译错误:
operator ==不能应用于"second.pckg.Category","first.pckg.Category"
import second.pckg.Category;
...
Category.JAZZ == item.getCategory()
Run Code Online (Sandbox Code Playgroud)
Chr*_*ell 13
这是一个粗略的时间测试来比较两者:
import java.util.Date;
public class EnumCompareSpeedTest {
static enum TestEnum {ONE, TWO, THREE }
public static void main(String [] args) {
Date before = new Date();
int c = 0;
for(int y=0;y<5;++y) {
for(int x=0;x<Integer.MAX_VALUE;++x) {
if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;}
if(TestEnum.ONE == TestEnum.TWO){++c;}
}
}
System.out.println(new Date().getTime() - before.getTime());
}
}
Run Code Online (Sandbox Code Playgroud)
一次一个地评论IF.以下是反汇编字节码中的两个比较:
21 getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
24 getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
27 invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28]
30 ifeq 36
36 getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
39 getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
42 if_acmpne 48
Run Code Online (Sandbox Code Playgroud)
第一个(等于)执行虚拟调用并测试堆栈中的返回布尔值.第二个(==)直接从堆栈中比较对象地址.在第一种情况下,有更多的活动.
我一次用两个IF运行这个测试几次."=="的速度要快得多.
小智 9
声纳规则之一是Enum values should be compared with "=="。原因如下:
测试枚举值的相等性
equals()是完全有效的,因为枚举是一个对象,每个 Java 开发人员都知道==不应该用于比较对象的内容。同时,==在枚举上使用:
提供相同的预期比较(内容)作为
equals()比空值更安全
equals()提供编译时(静态)检查而不是运行时检查
由于这些原因,
==应该优先使用equals()。
最后但并非最不重要的==一点是,on 枚举可以说比equals().
另一个选择是Objects.equals实用程序方法。
Objects.equals( thisEnum , thatEnum )
Run Code Online (Sandbox Code Playgroud)
Objects.equals 为零安全等于运算符==而不是.equals()
我应该使用哪个运算符?
第三个选项是在添加到Java 7及更高版本equals的Objects实用程序类上找到的静态方法。
这是使用Month枚举的示例。
boolean areEqual = Objects.equals( Month.FEBRUARY , Month.JUNE ) ; // Returns `false`.
Run Code Online (Sandbox Code Playgroud)
我发现此方法有很多好处:
truefalseNullPointerException所使用的逻辑是Objects.equals什么?
从OpenJDK的Java 10源代码中亲自了解一下:
return (a == b) || (a != null && a.equals(b));
Run Code Online (Sandbox Code Playgroud)
使用除==比较枚举常量之外的任何东西都是无稽之谈.这就像比较class对象equals - 不要这样做!
但是,Sun JDK 6u10及更早版本中存在一个令人讨厌的错误(BugId 6277781),由于历史原因这可能很有趣.这个错误阻止了==对反序列化枚举的正确使用,尽管这可以说是一个极端情况.
枚举是为public static final field(不可变)声明的每个枚举常量返回一个实例(如单例)的类,以便==运算符可用于检查它们的相等性而不是使用equals()方法
| 归档时间: |
|
| 查看次数: |
624116 次 |
| 最近记录: |