为什么返回null并分配给引用类型的三元条件表达式会导致NullPointerException?

我喜欢在java编程中使用三元条件表达式,但我遇到了一个问题:

以下代码是一个小例子,但它显示了我找到的问题。

public class Example { public Example() { Double x = 0.0; A a = new A(); x = a == null ? 0.0 : a.getY(); // Happens on this line System.out.println(x); } class A { Double y = null; private Double getY() { return y; } } public static void main(String[] args) { new Example(); } } 

导致NullPointerException什么?

这是由确定三元条件表达式类型的JLS规则产生的:

如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是对T应用装箱转换(第5.1.7节)的结果,那么条件表达式的类型是T.

此规则意味着三元表达式的类型是double而不是Double 。 将a.getY()方法返回的Double解包为double会导致NullPointerException ,因为该方法返回null

 a == null ? 0.0 : a.getY(); double Double -> hence the type of the ternary expression is double 

这是因为0.0double类型,而不是Double 。 条件运算符的后两个操作数必须是相同的类型,因此自动装箱/取消装箱进入它并且编译器将该代码转换为:

 x = Double.valueOf(a == null ? 0.0 : a.getY().doubleValue()); // -^^^^^^^^^^^^^^^--------------------------^^^^^^^^^^^^^^ 

…因为a.getY()返回null而抛出,然后代码尝试在null上调用doubleValue

如果我们运行javap -c Example来反编译代码,我们可以看到那些调用(我把它们换成粗体):

公共类示例{
   public Example();
    码:
        0:aload_0
        1:invokespecial#1 //方法java / lang / Object。“”:()V
        4:dconst_0
        5:invokestatic#2 //方法java / lang / Double.valueOf:(D)Ljava / lang / Double;
        8:astore_1
        9:new#3 // class示例$ A
       12:dup
       13:aload_0
       14:invokespecial#4 //方法示例$ A。“”:( LExample;)V
       17:astore_2
       18:aload_2
       19:ifnonnull 26
       22:dconst_0
       23:转到33
       26:aload_2
       27:invokestatic#5 //方法示例$ A.access $ 000 :( LExample $ A;)Ljava / lang / Double;
       30:invokevirtual#6 //方法java / lang / Double.doubleValue :()D 
        33:invokestatic#2 //方法java / lang / Double.valueOf:(D)Ljava / lang / Double;
       36:astore_1
       37:getstatic#7 // Field java / lang / System.out:Ljava / io / PrintStream;
       40:aload_1
       41:invokevirtual#8 //方法java / io / PrintStream.println:(Ljava / lang / Object;)V
       44:回归

   public static void main(java.lang.String []);
    码:
        0:new#9 // class示例
        3:重复
        4:invokespecial#10 //方法“”:()V
        7:流行
        8:回归
 }