代码之家  ›  专栏  ›  技术社区  ›  BalusC

布尔、条件运算符和自动装箱

  •  128
  • BalusC  · 技术社区  · 14 年前

    NullPointerException

    public static void main(String[] args) throws Exception {
        Boolean b = true ? returnsNull() : false; // NPE on this line.
        System.out.println(b);
    }
    
    public static Boolean returnsNull() {
        return null;
    }
    

    但这不是

    public static void main(String[] args) throws Exception {
        Boolean b = true ? null : false;
        System.out.println(b); // null
    }
    

    false 通过 Boolean.FALSE null 未绑定到 boolean --这是不可能的。但这不是问题所在。问题是 ? JLS中是否有任何参考资料证实了这种行为,尤其是第二种情况?

    4 回复  |  直到 12 年前
        1
  •  90
  •   Community CDub    7 年前

    returnsNull() 方法在编译时影响表达式的静态类型:

    E1: `true ? returnsNull() : false` - boolean (auto-unboxing 2nd operand to boolean)
    
    E2: `true ? null : false` - Boolean (autoboxing of 3rd operand to Boolean)
    

    请参阅Java语言规范一节 15.25 Conditional Operator ? :

    • 对于E1,第2和第3个操作数的类型是 Boolean boolean

      如果第二个和第三个操作数中的一个为布尔类型,而另一个为布尔类型,则条件表达式的类型为布尔类型。

      因为表达式的类型是 ,第二个操作数必须强制为 布尔型 返回单元格() )使之定型 . 这当然会导致 null 在运行时返回。

    • <special null type> (不是 布尔型 布尔型 所以没有特定的类型子句( go read 'em!

      否则,第二个和第三个操作数分别属于S1和S2类型。让T1是将装箱转换应用于S1的结果类型,让T2是将装箱转换应用于S2的结果类型。条件表达式的类型是将捕获转换(§5.1.10)应用于lub(T1,T2)的结果(§15.12.2.7)。

      • 第一节== <特殊空类型> (见 §4.1 )
      • 布尔型
      • T1==框(S1)== <特殊空类型> (请参阅中装箱转换列表中的最后一项 §5.1.7 )
      • T2==框(S2)==`Boolean
      • 布尔型

      布尔型 布尔型 . 编译器为第三个操作数插入自动装箱代码( false E1 ,因此当 无效的 被退回。


    这个问题需要类似的类型分析:

    Java conditional operator ?: result type

        2
  •  25
  •   peater dimitrisli    5 年前

    台词:

        Boolean b = true ? returnsNull() : false;
    

    内部转换为:

        Boolean b = true ? returnsNull().booleanValue() : false; 
    

    null.booleanValue() 将产生净现值

    5.1.8 JLS

    编辑:我认为取消装箱是由于第三个运算符是布尔类型,例如(添加了隐式强制转换):

       Boolean b = (Boolean) true ? true : false; 
    
        3
  •  16
  •   BalusC    14 年前

    Java Language Specification, section 15.25 :

    • 操作数的类型为布尔值,并且 另一个是Boolean类型, 那么条件的类型 表达式是布尔型的。

    所以,第一个例子试图调用 Boolean.booleanValue() Boolean boolean

    • 操作数的类型为S1和S2 分别是。让T1成为 转换为S1,并让T2为 应用拳击产生的类型 结果是条件表达式 应用捕获转换 (§5.1.10)至润滑油(T1,T2)(§15.12.2.7)。
        4
  •  0
  •   Yanhui Zhou    9 年前

    我们可以从字节码中看到这个问题。在main字节码的第3行, 3: invokevirtual #3 // Method java/lang/Boolean.booleanValue:()Z invokevirtual java.lang.Boolean.booleanValue ,当然会抛出NPE。

        public static void main(java.lang.String[]) throws java.lang.Exception;
          descriptor: ([Ljava/lang/String;)V
          flags: ACC_PUBLIC, ACC_STATIC
          Code:
            stack=2, locals=2, args_size=1
               0: invokestatic  #2                  // Method returnsNull:()Ljava/lang/Boolean;
               3: invokevirtual #3                  // Method java/lang/Boolean.booleanValue:()Z
               6: invokestatic  #4                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
               9: astore_1
              10: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
              13: aload_1
              14: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
              17: return
            LineNumberTable:
              line 3: 0
              line 4: 10
              line 5: 17
          Exceptions:
            throws java.lang.Exception
    
        public static java.lang.Boolean returnsNull();
          descriptor: ()Ljava/lang/Boolean;
          flags: ACC_PUBLIC, ACC_STATIC
          Code:
            stack=1, locals=0, args_size=0
               0: aconst_null
               1: areturn
            LineNumberTable:
              line 8: 0