为什么 Eclipse Java 编译器检查 null 类型转换?
考虑以下 Java 代码片段:
public class Test {
public static void use(Object[] x) {
}
public static void main(String[] args) {
Object[] x = null;
use(x);
}
}
Eclipse 3.7 编译器为 main()
生成的 Java 字节码如下所示:
public static void main(java.lang.String[]);
Code:
0: aconst_null
1: checkcast #20; //class "[Ljava/lang/Object;"
4: astore_1
5: aload_1
6: invokestatic #21; //Method use:([Ljava/lang/Object;)V
9: return
相反,这是 OpenJDK 1.6.0b22 编译器生成的字节码:
public static void main(java.lang.String[]);
Code:
0: aconst_null
1: astore_1
2: aload_1
3: invokestatic #2; //Method use:([Ljava/lang/Object;)V
6: return
请注意Eclipse 编译器发出额外的 checkcast
操作码。它似乎也只适用于数组,而不适用于任何其他变量类型。
我的问题:
据我所知,
null
可以分配给任何类,包括数组。checkcast
一个已知的null
值是否有意义?额外的
checkcast
会影响性能吗?这是否可以被视为 Eclipse Java 编译器中的错误?
注意:
我可以部分回答(2),至少就 OpenJDK 1.6.0b22 JVM 而言。我执行了一个简单的基准测试,在定时紧密循环中对 null
进行了多次赋值。我无法检测到任何一致的性能差异,无论是哪种方式。
也就是说,我的基准测试非常简单,任何半点优化器都可能使其毫无用处,因此它可能并不代表现实世界的应用程序。我希望 JVM总是优化该 checkcast
操作码,但情况可能并非如此。
Consider the following Java snippet:
public class Test {
public static void use(Object[] x) {
}
public static void main(String[] args) {
Object[] x = null;
use(x);
}
}
The Java bytecode produced for main()
by the Eclipse 3.7 compiler looks like this:
public static void main(java.lang.String[]);
Code:
0: aconst_null
1: checkcast #20; //class "[Ljava/lang/Object;"
4: astore_1
5: aload_1
6: invokestatic #21; //Method use:([Ljava/lang/Object;)V
9: return
On the contrary, this is the bytecode produced by the OpenJDK 1.6.0b22 compiler:
public static void main(java.lang.String[]);
Code:
0: aconst_null
1: astore_1
2: aload_1
3: invokestatic #2; //Method use:([Ljava/lang/Object;)V
6: return
Note that the Eclipse compiler issues an extra checkcast
opcode. It also seems to do that only for arrays and not for any other variable type.
My questions:
As far as I know,
null
is assignable to any class, including arrays. Does it make any sense at all tocheckcast
a knownnull
value?Does the extra
checkcast
affect performance?Could this be considered a bug in the Eclipse Java compiler?
NOTE:
I can partially answer (2), at least as far as the OpenJDK 1.6.0b22 JVM is concerned. I performed a simple benchmark with several assignments to null
in a timed tight loop. I could not detect any consistent performance difference, one way or the other.
That said, my benchmark was simple enough that any half-decent optimizer would have probably made it useless, so it may not be indicative of a real world application. I would expect that the JVM would always optimize out that checkcast
opcode, but that may not be the case.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
至于你的第一个问题,你是对的,那里的 checkcast 指令是多余的。
根据 Sun 的 Java Hotspot wiki,空检查和实例检查很便宜。
我已经在 Eclipse Bugzilla 中打开了一个问题,以获取来自 Eclipse 编译器的反馈团队,但正如之前指出的,这是多余的,但无害的检查。它仅影响字节码大小,Java HotSpot 编译器可能会在运行时应用类型检查优化。
更新:来自 Eclipse 编译器团队 这似乎是另一个老错误。
As for your first question, you are right, the checkcast instruction there is redundant.
According to Sun's Java Hotspot wiki null checks and instance checks are cheap.
I've opened an issue in Eclipse Bugzilla to get feedback from Eclipse compiler team, but as it been pointed out before, it is redundant, but harmless check. It only affects the bytecode size and Java HotSpot compiler will likely apply type check optimization at the runtime.
Update: from Eclipse compiler team it seem like as side effect of another old bug.
null
始终可转换为任何引用类型。但它不会伤害任何东西。ClassCastException
,因为该值始终是已知且正确的——而且,正如您显然所见看到了,无论哪种方式都没有真正的性能差异。这是一个改进的机会,但无论如何都不会破坏。null
is always castable to any reference type. But it doesn't hurt anything.ClassCastException
, as the value is always known and correct -- and, as you apparently saw, there's not a real performance difference either way. It's an opportunity for improvement, but nothing that will break in any case.它可能与 javac 中的已知错误有关:生成的代码中不必要的检查< /em>。
It might be related to a known bug in javac: Unnecessary checkcast in generated code.