Java8より前では、ほとんどの場合、†では、式の型は完全に下位式の型に依存してボトムアップされます。それは文脈に依存しません。これは素敵でシンプルであり、コードは分かりやすいです。たとえば、オーバーロードの解決は、メソッドの呼び出しコンテキストとは独立して解決される引数のタイプによって異なります。
(&ダガー、私の知る唯一の例外は、jls#15.12.2.8である)?int:Integer
の形で条件式を考える
、スペックは、コンテキストとは関係なく、それのために固定型を定義する必要があります。 int
タイプが選択されました。ほとんどのユースケースではおそらくこれが優れています。 もちろん、アンボックス化からのNPEのソースでもあります。
Java8では、コンテキスト・タイプの情報を型推論に使用できます。これは多くの場合に便利です。式の型を解決するには2つの方向があるかもしれないので、混乱も招く。幸いにも、いくつかの表現はまだ独立しています。それらの型は文脈に依存しない。
w.r.条件式では、false?0:1
のような簡単なものは文脈依存であるとは思わない。彼らのタイプは自明です。一方、false?f():g()
のようなより複雑な条件式についてはコンテキスト型の推論が必要です。ここで、f/g()
には型推論が必要です。
このラインは、原型と参照型の間に描かれました。 op1?op2:op3
では、op2
とop3
の両方が「はっきり」のプリミティブタイプ(またはボックス版)である場合、スタンドアロンとして扱われます。 Quotingダン・スミス -
は、我々はブール値と数値条件文の既存の動作を維持しながら、参照条件文(15.25.3)の型付け規則を強化するために、ここで条件式を分類します。すべての条件を一様に扱おうとすると、過負荷の解決やボクシング/アンボクシングの動作の変更など、さまざまな望ましくない互換性のない変更が発生します。 false?4:null
以来
あなたの場合
Integer x = false ? 3 : false ? 4 : null;
"明確に" Integer
で、親式は?:int:Integer
の形態です(?)。これは原始的なケースであり、その動作はjava7との互換性を維持しているため、NPEです。
これは私の直感的な理解であるため、「明確に」引用しています。私は正式な仕様についてはわかりません。この例を見てみましょう
static <T> T f1(){ return null; }
--
Integer x = false ? 3 : false ? f1() : null;
コンパイル!実行時にはNPEはありません!私はこの場合の仕様に従う方法を知らない。コンパイラはおそらく次のステップを実行すると思います:
1)サブ式false?f1():null
は「はっきり」(ボックス化された)プリミティブ型ではありません。そのタイプは未知であるが、
2)したがって、親表現は、「参照条件式」として分類コンテキストに現れる。
3)ターゲット・タイプInteger
は、オペランドに適用され、その後、推定され、最終的にf1()
は、我々はすぐに戻って行くことができない?int:Integer
としての条件式を再分類する、しかし)Integer
4を返すために、 。
これは妥当と思われます。しかし、型引数を明示的にf1()
に指定するとどうなりますか?
Integer x = false ? 3 : false ? Test.<Integer>f1() : null;
理論(A) - それは推測されていたであろうと同じタイプの引数だから、これは、プログラムのセマンティクスを変更しないでください。私たちは実行時にNPEを見るべきではありません。
理論(B) - 型推論はありません。サブ式のタイプは明らかにInteger
なので、これは原始的なケースとして分類されるべきであり、実行時にNPEを参照する必要があります。
私は(B)を信じています。しかし、javac(8u60)は(A)を実行します。なぜか分からない。
意味をなさない陽気なレベル
class MyList1 extends ArrayList<Integer>
{
//inherit public Integer get(int index)
}
class MyList2 extends ArrayList<Integer>
{
@Override public Integer get(int index)
{
return super.get(0);
}
}
MyList1 myList1 = new MyList1();
MyList2 myList2 = new MyList2();
Integer x1 = false ? 3 : false ? myList1.get(0) : null; // no NPE
Integer x2 = false ? 3 : false ? myList2.get(0) : null; // NPE !!!
にこの観察を押します。 javacの中で何か本当にファンキーなことが起こっています。
(Java autoboxing and ternary operator madnessも参照)
オートボックを調べます。 –
nullポインタへのアクセス:Integer型のこの式はnullですが、自動アンボッキングが必要です –
これらの質問も参照してください:[Java autoboxing and ternary madness](http://stackoverflow.com/questions/25417438/java-autoboxing-and-ternary -operator-madness)と[Java 3値の自動ボクシングによるNPE](http://stackoverflow.com/questions/12763983/nullpointerexception-through-auto-boxing-behavior-of-java-ternary-operator)を参照してください。 –