为什么这段代码会编译?我原以为编译器会抱怨"类型不匹配:无法从null转换为布尔值"但它并没有。它只是在运行时失败并出现NullPointerException。
public static void main(String[] args) throws Exception {
System.out.println("this throws a NPE: " + whyIsThisPossible(1, 2));
}
private static boolean whyIsThisPossible(int a, int b) {
return a + b == 2 ? true : null;
}
Exception in thread "main" java.lang.NullPointerException
at FunkyMethodTest.whyIsThisPossible(FunkyMethodTest.java:10)
at FunkyMethodTest.main(FunkyMethodTest.java:5)*
答案 0 :(得分:3)
Java认为三元表达式的类型为boolean
。编译器将null
视为Boolean
,即将装箱转换应用于原始类型boolean
的结果。
以下是语言规范的相关部分:
15.25 条件表达式的类型确定如下:
...
- 如果第二个和第三个操作数之一是基本类型
T
,而另一个操作数的类型是将装箱转换(第5.1.7节)应用于T
的结果,那么类型条件表达式是T
。
语言规范指出装箱/取消装箱转换在必要时应用于由表达式条件选择的操作数。这是代码尝试从boolean
取消装箱null
时触发异常的原因。
答案 1 :(得分:0)
三元组的第一部分确定操作数类型,在本例中为原始boolean
。
return a + b == 2 ? true : null;
请注意,您可以(语法上)将null
(技术上为NullType)转换为boolean
,但会产生NullPointerException
。因此,在代码编译时,如果a + b
不等于2
,则会得到NullPointerException
。至于为什么它在语法上是合法的,请考虑
return a + b == 2 ? true : Boolean.FALSE;
请注意,Boolean.FALSE
是Boolean
,自动装箱意味着此代码正常运行。
答案 2 :(得分:0)
这个return a + b == 2 ? true : (Boolean) x;
实际发生了,虽然你实际上写不出来,因为编译器会抱怨。但你可以写:
private static boolean whyIsThisPossible(int a, int b) {
Boolean x = null;
if (a == b) {
x = false;
}
return a + b == 2 ? true : (Boolean) x;
}