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

时间:2015-08-17 10:24:58

标签: java eclipse-jdt

我经常使用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在他的回答中注意到,类型检查的实例不是Eclipse中的默认设置,所以我编辑了这个问题。但这并没有改变任何事情。

另外请不要建议我使用getClass()或(甚至更好!)一个不同的IDE。这不是重点,没有回答这个问题。我没有就如何编写equals()实现提出建议,无论是使用instanceof还是getClass()等。

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

2 个答案:

答案 0 :(得分:3)

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

因此,单独的空检查可能是性能改进。 快速测量并且没有惊喜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);
    }
}

答案 1 :(得分:2)

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

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编写代码模板的人也值得他们的盐。" ,我认为他们是但是要注意这些微小的不一致并不会伤害他们。 :)