Lio*_*ion 185 java autoboxing nullpointerexception conditional-operator
让我们看看以下代码段中的简单Java代码:
public class Main {
private int temp() {
return true ? null : 0;
// No compiler error - the compiler allows a return value of null
// in a method signature that returns an int.
}
private int same() {
if (true) {
return null;
// The same is not possible with if,
// and causes a compile-time error - incompatible types.
} else {
return 0;
}
}
public static void main(String[] args) {
Main m = new Main();
System.out.println(m.temp());
System.out.println(m.same());
}
}
Run Code Online (Sandbox Code Playgroud)
在这个最简单的Java代码中,temp()即使函数的返回类型是int,我们尝试返回值null(通过语句return true ? null : 0;),该方法也不会发出编译器错误.编译时,这显然会导致运行时异常NullPointerException.
但是,如果我们用一个if语句(如same()方法中)表示三元运算符,它会发出编译时错误,这似乎是错误的!为什么?
Ted*_*opp 115
编译器将其解释null为对a的空引用Integer,对条件运算符应用自动装箱/取消装箱规则(如Java语言规范,15.25中所述),并愉快地进行操作.这将生成一个NullPointerException运行时,您可以通过尝试来确认.
Jon*_*rdy 25
在if语句的情况下,null引用不被视为Integer引用,因为它没有参与强制它被解释为这样的表达式.因此,错误可以在编译时轻松捕获,因为它更明显是类型错误.
至于条件运算符,Java语言规范§15.25"条件运算符? :"在如何应用类型转换的规则中很好地回答了这个问题:
- 如果第二个和第三个操作数具有相同的类型(可以是null类型),那么这就是条件表达式的类型.
不适用,因为null不是int.
- 如果第二个和第三个操作数之一是boolean类型,另一个类型是Boolean类型,那么条件表达式的类型是boolean.
不适用,因为既没有null,也不int是boolean或Boolean.
- 如果第二个和第三个操作数之一是null类型而另一个操作数的类型是引用类型,则条件表达式的类型是该引用类型.
不适用,因为null属于null类型,但int不是引用类型.
- 否则,如果第二个和第三个操作数具有可转换(第5.1.8节)到数字类型的类型,则有几种情况:[...]
适用:null被视为可转换为数字类型,并在第5.1节中定义. 8"取消装箱转换"抛出一个NullPointerException.
Mar*_*ace 11
首先要记住的是Java三元运算符具有"类型",这就是编译器将确定和考虑的内容,无论第二个或第三个参数的实际/实际类型是什么.根据几个因素,三元运算符类型以不同的方式确定,如Java语言规范15.26中所示
在上面的问题中,我们应该考虑最后一个案例:
否则,第二和第三操作数分别是S1和S2类型.设T1是将拳击转换应用于S1所产生的类型,让T2为应用到S2的装箱转换所产生的类型.条件表达式的类型是将捕获转换(第5.1.10节)应用于lub(T1,T2)(第15.12.2.7节)的结果.
一旦你看一下应用捕获转换(第5.1.10节)并且最重要的是在lub(T1,T2)上,这是迄今为止最复杂的情况.
用简单的英语和极端简化后,我们可以将过程描述为计算第二和第三参数的"最小公共超类"(是的,想想LCM).这将为我们提供三元运算符"类型".同样,我刚才所说的是极端简化(考虑实现多个通用接口的类).
例如,如果您尝试以下操作:
long millis = System.currentTimeMillis();
return(true ? new java.sql.Timestamp(millis) : new java.sql.Time(millis));
Run Code Online (Sandbox Code Playgroud)
您会注意到条件表达式的结果类型是java.util.Date因为它是Timestamp/ Timepair 的"最小公共超类" .
由于null可以自动装箱到任何东西,"最小公共超类"是Integer类,这将是上面条件表达式(三元运算符)的返回类型.返回值将是类型的空指针,Integer这将是三元运算符返回的值.
在运行时,Java虚拟机unboxes的Integer一个NullPointerException被抛出.发生这种情况是因为JVM尝试调用该函数null.intValue(),其中null是自动装箱的结果.
在我看来(因为我的观点不在Java语言规范中,很多人会发现它错了)编译器在评估你的问题中的表达式时表现不佳.鉴于您编写true ? param1 : param2的编译器应立即确定第一个参数null- 将返回,它应该生成编译器错误.这有点类似于你编写时while(true){} etc...,编译器抱怨循环下面的代码并标记它Unreachable Statements.
你的第二个案例非常简单,这个答案已经太长了......;)
更正:
经过另一次分析后,我认为我说错了null可以装箱/自动装箱任何东西.谈论类Integer,显式装箱包括调用new Integer(...)构造函数或者Integer.valueOf(int i);(我在某处找到了这个版本).前者会抛出NumberFormatException(这不会发生),而第二种情况则没有意义,因为int不能null......
| 归档时间: |
|
| 查看次数: |
15009 次 |
| 最近记录: |