为什么 Eclipse 生成的 equals() 实现在类型检查(instanceof)之前检查是否为 null?
Why does the equals() implementation generated by Eclipse check for null before type checking (instanceof)?
我经常使用 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 语句根本没有必要,因为只要 obj 为 null,instanceof 类型检查就会 return false。 (See question 3328138.)
现在,我猜那些为 Eclipse JDT 编写代码模板的人也值得一试。所以我想肯定有一些空检查的原因,但我不确定它是什么?
(另外 question 7570764 可能会给出一个提示:如果我们使用 getClass() 比较而不是 instanceof 进行类型检查,obj.getClass() 不是 null 安全的。也许代码模板不聪明如果我们使用 instanceof 就足以省略 null 检查。)
编辑:Dragan 在他的回答中注意到,instanceof 类型检查不是 Eclipse 中的默认设置,因此我将其编辑为排除了问题。但这并没有改变任何东西。
另外请不要建议我使用 getClass() 或(甚至更好!)不同的 IDE。那不是重点,那不回答问题。我没有征求关于如何编写 equals() 实现、是否使用 instanceof 或 getClass() 等的建议
问题大致是:这是Eclipse中的一个小错误吗?如果不是,那为什么它有资格成为一项功能?
确实没有必要,是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
是,则]
.
前会有一个额外的逗号
所以,关于你的陈述:"Now, I guess that the folks writing the code templates for Eclipse JDT are worth their salt, too.",我认为他们是,但更多地关注这些微小的不一致不会伤害他们。 :)
这是不必要的,因为 instanceof 有一个内置的空检查。
但是 instanceof 远不止简单的 foo == null。这是一个完整的说明,准备 class 检查在空检查完成之前做不必要的工作。 (详见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 的代码生成工具(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 语句根本没有必要,因为只要 obj 为 null,instanceof 类型检查就会 return false。 (See question 3328138.)
现在,我猜那些为 Eclipse JDT 编写代码模板的人也值得一试。所以我想肯定有一些空检查的原因,但我不确定它是什么?
(另外 question 7570764 可能会给出一个提示:如果我们使用 getClass() 比较而不是 instanceof 进行类型检查,obj.getClass() 不是 null 安全的。也许代码模板不聪明如果我们使用 instanceof 就足以省略 null 检查。)
编辑:Dragan 在他的回答中注意到,instanceof 类型检查不是 Eclipse 中的默认设置,因此我将其编辑为排除了问题。但这并没有改变任何东西。
另外请不要建议我使用 getClass() 或(甚至更好!)不同的 IDE。那不是重点,那不回答问题。我没有征求关于如何编写 equals() 实现、是否使用 instanceof 或 getClass() 等的建议
问题大致是:这是Eclipse中的一个小错误吗?如果不是,那为什么它有资格成为一项功能?
确实没有必要,是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
是,则]
.
所以,关于你的陈述:"Now, I guess that the folks writing the code templates for Eclipse JDT are worth their salt, too.",我认为他们是,但更多地关注这些微小的不一致不会伤害他们。 :)
这是不必要的,因为 instanceof 有一个内置的空检查。 但是 instanceof 远不止简单的 foo == null。这是一个完整的说明,准备 class 检查在空检查完成之前做不必要的工作。 (详见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);
}
}