1. ホーム
  2. java

[解決済み] ブール演算子、条件演算子、自動ボックス化

2022-06-09 01:39:28

質問

なぜ 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
}

?

解決策としては falseBoolean.FALSE を避けるために null にアンボックスされる。 boolean --というのはありえないことです。しかし、それは問題ではありません。問題は なぜ ? この挙動、特に2番目のケースについて、JLSで確認した文献はありますか?

どのように解決するのですか?

違いは、明示的な型である 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 条件演算子 ?

  • E1では、第2オペランドと第3オペランドの型は Boolean であり boolean というように、この節が適用されます。

    第2オペランドと第3オペランドの一方がboolean型で、もう一方の型がboolean型の場合、条件式の型はboolean型となります。

    式の型は boolean であるため、2番目のオペランドは強制的に boolean . コンパイラは自動アンボックスコードを第2オペランドに挿入します(返り値は returnsNull() の戻り値) に自動アンボックスコードを挿入し、それを boolean . もちろん、これは null がランタイムに返されます。

  • E2の場合、第2オペランドと第3オペランドの型は <special null type> (です(ただし Boolean のように!)、そして boolean のように、それぞれ、特定の型付け句は適用されません ( を読みに行く! )なので、最後の "others"節が適用されます。

    さもなければ、第2、第3オペランドはそれぞれS1、S2型である。S1に箱詰め変換を適用した結果の型をT1、S2に箱詰め変換を適用した結果の型をT2とする。条件式の型は、lub(T1, T2) (§15.12.2.7) に捕捉変換 (§5.1.10) を適用した結果である。

    • S1 == <special null type> (参照 §4.1 )
    • S2 == boolean
    • T1 == box(S1)==」です。 <special null type> (のボクシング変換のリストの最後の項目を参照してください)。 §5.1.7 )
    • T2 == box(S2) == `ブール値
    • lub(T1, T2) == `ブール値 Boolean

    つまり、条件式の型は Boolean で、3番目のオペランドは強制的に Boolean . コンパイラは3番目のオペランドに自動ボックス化コードを挿入します ( false ). 2 番目のオペランドは、次のように自動解凍を必要としません。 E1 のように自動アンボックスを必要としないので、自動アンボックスのNPEは発生しません。 null が返されても自動アンボックスのNPEは発生しません。


この質問には、同じようなタイプの分析が必要です。

Java条件演算子 ?: 結果の型