我最近尝试运行以下两段代码,并对输出感到惊讶。
第一:
// ...
System.out.println( (Boolean)null || true );
// ...
第二:
// ...
System.out.println( (Boolean)null || false );
// ...
第一个例子产生以下输出:
真
第二个例子产生以下输出:
线程“main”中的异常java.lang.NullPointerException
在com.blah.main(SanityCheck.java:26)
我原以为这两个例子都会导致空指针异常,因为任何短路都是从左到右应用的。从布尔中取消装箱布尔值的尝试应该在逻辑的另一侧之前失败或者被考虑。
任何人都可以解释这种不一致的行为吗?
答案 0 :(得分:4)
我通过JAD运行类文件,看看优化代码的样子。对于真实案例:
// ...
System.out.println(true);
// ...
对于虚假案件:
// ...
System.out.println(null.booleanValue());
// ...
答案 1 :(得分:2)
我会抨击它。 当编译器试图解释这两个语句时,主要区别在于右侧的true语句不需要使用左手布尔值进行计算,而右侧的语句是false。
布尔值是一个Object,因此可以设置为null。这不是引发异常的地方。当您尝试对设置为null的Boolean对象执行操作时,将引发NullPointerException。在真实情况下,编译器会将cast null传递给Boolean,并且因为OR与true将始终为true,因此条件为true。在false的情况下,编译器会再次将cast null传递给Boolean,然后检查false,如果条件为false,则需要使用Boolean计算OR,因为条件最终可能为true或false。计算发生时,抛出NullPointerException。
答案 2 :(得分:1)
我无法重现您的结果。我实际上在两种情况下都获得了NPE。
根据JLS,始终首先评估左侧操作数表达式。在评估(Boolean)null
时,会对null布尔对象执行自动拆箱。特别是,底层代码null.booleanValue()
正在导致NPE。