違いは、コンパイル時の式の静的型付けです。
概要
E1: `(false ? 1.0f : null)`
- arg 2 '1.0f' : type float,
- arg 3 'null' : type null
- therefore operator ?: : type Float (see explanation below)
- therefore autobox arg2
- therefore autobox arg3
E2: `(false ? 1.0f : (false ? 1.0f : null))`
- arg 2 '1.0f' : type float
- arg 3 '(false ? 1.0f : null)' : type Float (this expr is same as E1)
- therefore, outer operator ?: : type float (see explanation below)
- therefore un-autobox arg3
詳細な説明:
これは、仕様を読み、得られた結果から逆方向に作業することから得た私の理解です。つまり、f2内部条件の第 3 オペランドの型は null 型であり、f2外部条件の第 3 オペランドの型は Float と見なされます。
注:タイプの決定とボックス化/ボックス化解除コードの挿入はコンパイル時に行われることに注意してください。ボックス化/ボックス化解除コードの実際の実行は、実行時に行われます。
Float f1 = (false ? 1.0f : null);
Float f2 = (false ? 1.0f : (false ? 1.0f : null));
f1 条件と f2 内部条件: (false ? 1.0f : null)
f1 条件と f2 内部条件は同一です: (false ? 1.0f : null)。f1 条件と f2 内部条件のオペランドの型は次のとおりです。
type of second operand = float
type of third operand = null type (§4.1)
§15.25のルールのほとんどは無視され、この最終評価が実際に適用されます。
それ以外の場合、2 番目と 3 番目のオペランドの型はそれぞれ S1 と S2 です。T1 を S1 にボックス化変換を適用した結果の型とし、T2 を S2 にボックス化変換を適用した結果の型とする。条件式の型は、キャプチャ変換 ( §5.1.10 ) を lub(T1, T2) ( §15.12.2.7 ) に適用した結果です。
S1 = float
S2 = null type
T1 = Float
T2 = null type
type of the f1 and f2 inner conditional expressions = Float
f1 は Float 参照変数への代入であるため、式の結果 (null) は正常に代入されます。
f2 外部条件の場合: (false ? 1.0f : [f2 内部条件])
f2 外部条件の場合、型は次のとおりです。
type of second operand = float
type of third operand = Float
nullリテラルを直接参照する f1/f2 内部条件と比較したオペランドの型の違いに注意してください( §4.1 )。数値変換可能な型が 2 つあるというこの違いにより、§15.12.2.7の次の規則が適用されます。
f2 内部条件 (null) の結果に対してボックス化解除変換が実行されるため、NullPointerException が発生します。