为啥 Eclipse 生成的 equals() 实现会在类型检查(instanceof)之前检查 null?

Posted

技术标签:

【中文标题】为啥 Eclipse 生成的 equals() 实现会在类型检查(instanceof)之前检查 null?【英文标题】:Why does the equals() implementation generated by Eclipse check for null before type checking (instanceof)?为什么 Eclipse 生成的 equals() 实现会在类型检查(instanceof)之前检查 null? 【发布时间】:2015-11-09 22:48:20 【问题描述】:

我经常使用 Eclipse 的代码生成工具(Source / Generate hashCode() 和 equals()...)为简单的 POJO 类创建 equals() 实现。如果我选择“使用 instanceof 来比较类型”,则会产生类似于以下的 equals() 实现:

  @Override
  public boolean equals(Object obj) 
      if (this == obj) 
          return true;
      
      if (obj == null) 
          return false;
      
      if (!(obj instanceof MyClass)) 
          return false;
      
      MyClass other = (MyClass) obj;
      // check the relevant fields for equality
  

今天一位同事指出,第二个if语句根本不需要,因为只要obj为null,instanceof类型检查就会返回false。 (See question 3328138.)

现在,我想那些为 Eclipse JDT 编写代码模板的人也值得一试。所以我认为空检查一定有一些原因,但我不确定它是什么?

(另外question 7570764 可能会给出提示:如果我们使用 getClass() 比较进行类型检查而不是 instanceof,则 obj.getClass() 不是 null 安全的。也许代码模板不够聪明,无法省略 null 检查如果我们使用 instanceof。)

编辑:Dragan 在他的回答中注意到,instanceof 类型检查不是 Eclipse 中的默认设置,所以我编辑了这个问题。但这不会改变任何事情。

另外请不要建议我应该使用 getClass() 或(甚至更好!)不同的 IDE。这不是重点,这不能回答问题。我没有就如何编写equals()实现、是否使用instanceof或getClass()等征求意见。

问题大致是:这是 Eclipse 中的一个小错误吗?如果不是,那为什么它可以作为一项功能呢?

【问题讨论】:

不知道,但 instanceof 并不总是被认为是最好的方法。另一种方法是将 obj.getClass() 与 this.getClass() 进行比较,然后您确实需要进行 null 检查 我会引用a comment on this answer。 Specifically, in Item 8, he notes that in equals() methods, one instanceof operator serves two purposes - it verifies that the argument is both non-null and of the correct type. "...[S]o you don't need a separate null check." IntelliJ Idea 生成一个包含null 检查的equals implementation,但使用的是getClass()if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; /*...*/ 使用 Eclipse Luna。空检查后生成的代码getClass() != obj.getClass() Any reason to prefer getClass() over instanceof when generating .equals() 很好地介绍了是否使用instanceofgetClass()。 Josh Bloch 喜欢使用instanceof;他的论点可以从this (old) interview找到。 【参考方案1】:

这是不必要的,因为 instanceof 有一个内置的空检查。 但是 instanceof 不仅仅是一个简单的 foo == null。这是一个完整的指令,在完成空检查之前准备类检查做不必要的工作。 (详情请参阅http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.instanceof)

因此,单独的 null 检查可能会提高性能。 进行了快速测量,毫不奇怪 foo==null 比使用 instanceof 进行 nullcheck 更快。

但通常情况下,equals() 中没有大量的空值,而大多数情况下,您需要重复不必要的空值检查...这可能会消耗空值比较期间所做的任何改进。

我的结论:没有必要。

用于测试完整性的代码(记得使用 -Djava.compiler=NONE 否则你只会衡量 java 的能力):

public class InstanceOfTest 
    public static void main(String[] args) 
        Object nullObject = null;

        long start = System.nanoTime();         
        for(int i = Integer.MAX_VALUE; i > 0; i--) 
            if (nullObject instanceof InstanceOfTest) 
        
        long timeused = System.nanoTime() - start;  

        long start2 = System.nanoTime();
        for(int i = Integer.MAX_VALUE; i > 0; i--) 
            if (nullObject == null) 
        
        long timeused2 = System.nanoTime() - start2;

        System.out.println("instanceof");
        System.out.println(timeused);       
        System.out.println("nullcheck");
        System.out.println(timeused2);
    

【讨论】:

我确信 instanceof 指令在内部空值检查之前所做的事情与手动空值检查相比微不足道,尤其是在优化的环境中。 在优化的环境中,我希望“手动”nullcheck 的优化与内部的一样好。 (说汇编程序都会归结为 MOV CMP JNE ) Instanceof 作为指令使用堆栈有一个pop(引用),push(结果)比一个简单的nullcheck。这在现实中会用掉多少很难说,并且可能因操作系统和硬件而异。 (这就是为什么分析是检查性能问题的理想选项)【参考方案2】:

确实,这是不必要的,这是 Eclipse 模板作者的错误。这不是第一个;我在那里发现了更多更小的错误。比如我想省略null值时toString()方法的生成:

public class A 
    private Integer a;
    private Integer b;

    @Override
    public String toString() 
        StringBuilder builder = new StringBuilder();
        builder.append("A [");
        if (a != null)
            builder.append("a=").append(a).append(", ");
        if (b != null)
            builder.append("b=").append(b);
        builder.append("]");
        return builder.toString();
    

如果a 不是nullb 是,则在结束] 之前会有一个额外的逗号。

所以,关于您的陈述:“现在,我想为 Eclipse JDT 编写代码模板的人也值得他们的盐分。”,我认为他们是,但不会有坏处他们要更加注意这些微小的不一致。 :)

【讨论】:

好的,现在我不确定默认是什么(或曾经是什么),所以我编辑了该部分。

以上是关于为啥 Eclipse 生成的 equals() 实现会在类型检查(instanceof)之前检查 null?的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse生成的hashCode函数好用吗?

JAVA中重写equals方法为啥要重写hashcode方法说明

Eclipse做C程序时为啥Debug下不能生成exe文件,新手在线等帮助,悬赏!

用eclipse生成JAR文件,为啥main class项啥都没有?

为啥eclipse每次新建项目时都会出现一个错误弹窗,并会在src下自动生成module-info.java文档?

为啥我的maven 生成的目录不对?