出于某种原因,以下代码正常编译:
public double getSomeDouble() {
return "" != null ? 3.7d : null;
}
我通常希望Eclipse将其标记为错误(null
无法转换为double
原语。
回到我的假设,这段代码不起作用:
public double getSomeDouble() {
return null;
}
Eclipse会将return null
行标记为错误,并说明:
类型不匹配:无法从
null
转换为double
为什么它在前面的代码片段中没有说同样的内容?!
答案 0 :(得分:23)
归因于autoboxing和autounboxing。如果你查看字节码(下面),你可以看到对Double.valueOf
的调用(装箱3.7d
)和Double#doubleValue
(取消装箱条件表达式的结果)。条件运算符的操作数必须是相同的类型,因此编译器有效地将您的代码转换为:
public double getSomeDouble() {
return ("" != null ? Double.valueOf(3.7d) : null).doubleValue();
}
...因为Double
是3.7d
和null
可以找到的最具体的常见类型。
我使用了一个字符串参数(以消除围绕不变表达式"" != null
的编译器优化,编译器能够告诉它永远不会是真的):
public double getSomeDouble(String str) {
return str != null ? 3.7d : null;
}
实际上变成了:
public double getSomeDouble(String str) {
return (str != null ? Double.valueOf(3.7d) : null).doubleValue();
}
...当我在null
传递str
时,当它试图在doubleValue()
上调用null
时,确实在运行时获得了NPE。
这是我getSomeDouble(String)
的字节码(来自javap -c MyClass
):
public double getSomeDouble(java.lang.String); Code: 0: aload_1 1: ifnull 13 4: ldc2_w #7 // double 3.7d 7: invokestatic #9 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double; 10: goto 14 13: aconst_null 14: invokevirtual #10 // Method java/lang/Double.doubleValue:()D 17: dreturn