[英]Why does the equals() implementation generated by Eclipse check for null before type checking (instanceof)?
我经常使用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。 ( 见问题3328138. )
现在,我想那些为Eclipse JDT编写代码模板的人也值得他们的盐。 所以我认为这个空检查必须有一些原因,但我不确定它是什么?
(还有问题7570764可能会给出一个提示:如果我们使用getClass()比较进行类型检查而不是instanceof,obj.getClass()不是null安全的。如果我们使用instanceof,可能代码模板不够聪明,不能忽略null检查。)
编辑:Dragan在他的回答中注意到,类型检查的instanceof不是Eclipse中的默认设置,所以我编辑了这个问题。 但这并没有改变任何事情。
另外请不要建议我使用getClass()或(甚至更好!)一个不同的IDE。 这不是重点,不能回答这个问题。 我没有询问有关如何编写equals()实现的建议,无论是使用instanceof还是getClass()等。
问题大致是:这是Eclipse中的一个小错误吗? 如果不是,那为什么它有资格成为一个功能?
这是不必要的,因为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);
}
}
实际上,这是不必要的,这是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
不是null
和b
是,会有闭幕前一个逗号]
。
所以,关于你的陈述: “现在,我想那些为Eclipse JDT编写代码模板的人也值得他们的盐。” ,我认为它们是,但是不要太注意这些微小的不一致。 :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.