値を割り当てるときの奇妙なJavaの3値の動作。これが起こるためにJavaは舞台裏で何をしていますか?


10

数日前、私は、Javaが次のことをどのように、またはなぜ可能にするのかについてのドキュメントを見つけることができなかった興味深いシナリオに遭遇しました。(このスニペットは、バグを単純化したものです。)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

上記のスニペットで:

bool = trueの場合、値は「5」になります。

しかし、bool = falseの場合、3項演算を評価しようとすると、nullポインタ例外が発生します。印刷ステートメントではありません。


これを修正するには、「結果」を次のように変更します

Long result = bool ? Long.valueOf(intVal) : longVal;

これを行うと、私が必要とする期待される動作が得られます:

bool = trueの場合、値は「5」になります。

しかし、bool = falseの場合、「null」になります。


楽しい部分は、これを通常のif / elseステートメントに分割した場合、Javaではコンパイルできないことです。

longVal = intVal; 

しかし、三項演算子を介してそれをキャッチしません。それで、元のスニペットでそれをヌルポイントにするためにJavaは何をしていますか?

(Java 11)

回答:


10

これを行うと:

Long result = bool ? intVal : longVal

この式はa longを返し、boolがfalseの場合null、Long値にボックス化解除して、result変数、NPEをスローします。

これを行うと:

Long result = bool ? Long.valueOf(intVal) : longVal

この式はすでに返さLongれているため、ボックス化を解除する必要はなく、null値はresult変数に正常に割り当てられます。

参照:

コメントセクションで説明したように、これが発生する理由をよりよく理解するには、JLSの以下のセクションを確認してください。


異なる参照テーブル15.25 AからEに驚かされます。ここで、Integer / Longがbnp(Integer、Long)になることが「明確」です。
マット

いい答えです。一般に、内部で何が起こっているのかまったくわからない場合は、コンパイルされたバイトコードを確認することをお勧めします。これにより、記述内容がほぼ正確に明らかになります。少なくとも、最小限のコードスニペットを抽出する場合、それは多かれ少なかれトレーニングの問題であり、それを読み、理解する方法です。
Janは

JLSと同じように、セクション5.6.2は次のように述べています。「オペランドが参照型である場合、それはボックス化解除の対象になります」。次に「拡張プリミティブ変換(§5.1.2)が適用されます[..]」
ディエゴマグダ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.