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

17 浏览
0 Comments

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

我经常使用Eclipse的代码生成工具 (Source / Generate hashCode() and equals()...) 来为简单的POJO类创建equals()实现。如果选取 “Use instanceof to compare types” 选项,将会产生一个类似下面的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语句根本不必要,因为instanceof类型检查在obj为null时会返回false。 (详见问题3328138。)

现在,我猜测编写Eclipse JDT代码模板的人员也值得信赖。所以我想它肯定有某种原因,需要进行null检查,但我不太确定是什么原因?

(此外,问题7570764可能会给提示:如果我们使用getClass()进行类型检查而不是instanceof,那么obj.getClass()就不是null安全的。也许代码模板只是不聪明到可以在使用instanceof时省略null检查。)

编辑:Dragan在他的回答中提到,instanceof类型检查不是Eclipse的默认设置,所以我将其从问题中删除了。但这并不改变任何事情。

同时,请不要建议我使用getClass()或(更好的是!)使用另一个IDE。这不是重点,这不回答问题。我没有要求关于如何编写equals()实现以及是否使用instanceof或getClass()等的建议。

问题大致是:这是Eclipse中的一个小bug吗?如果不是,那么它为什么算是一个特性?

admin 更改状态以发布 2023年5月21日
0
0 Comments

事实上,这完全没有必要,而且这是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代码模板的人也是值得信赖的”,我想他们是,但如果他们更加注重这些微小的不一致性,那也不会对他们造成伤害。 🙂

0
0 Comments

这是不必要的,因为instanceof有一个内置的null检查。 但instanceof不仅仅是一个简单的foo == null。 它是一条完整的指令,准备一个类检查,在进行空检查之前做不必要的工作。(有关更多详细信息,请参见http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.instanceof

因此,单独的空检查可能会提高性能。 快速测试并不意外,foo==null比使用instanceof的空检查更快。

但通常您不会在equals中有大量的null值,这使得您大部分时间都不需要使用重复的不必要的空检查...这可能会消耗任何进行空比较所做的改进。

我的结论:这是不必要的。

用于完整测试的代码(记得使用-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);
    }
}

0