Java5で条件演算子(三項演算子)に仕様変更があった!

昨日の「条件演算子(三項演算子)で、:の左側と右側に共通のインタフェースを持つ別のクラスを書く」についての追記です。

C#だと、以下のように条件演算子のふたつの式が共通の型を持っている場合でもコンパイルエラーになりますが、Javaだとちゃんとコンパイルできます。

/* -- Java -- */
public interface X { ・・・ }
public class A implements X { ・・・ }
public class B implements X { ・・・ }

public void test(boolean isFirst){
    X x = isFirst ? new A() : new B();    // OK
    ・・・
}


これは、Javaの言語仕様が・・・

  • 2番目と3番目のオペランドが同じ型である場合、(null 型でも可)、それがこの条件式の型となる。

(中略)

  • さもなければ、2番目と3番目のオペランドの型をそれぞれ S1 と S2 とする。そして、S1 に対するボクシング変換の適用結果を T1、S2に対するボクシング変換の適用結果を T2 とする。この条件式の型は、lub(T1, T2)*1 (§15.12.2.7*2)に対する補足変換(§5.1.10)の適用結果となる。
§15.25 条件演算子?:(Java言語仕様 第3版)

となっていることに基づきます。


ただ、これは Java5 以降で可能になったものでした。*3


言語仕様の第2版(〜Java 1.4)まではC#と同じような仕様なので、コンパイルエラーになります。

2番目及び3番目のオペランドが異なる参照型ならば,型の一つが他の型に代入変換(5.2) によって変換可能でなければならない(変換された後の型を,ここではTと呼ぶ)。この場合,条件式の型はTとする。もしどちらの型も他方の型に代入互換でないならば,コンパイル時エラーとする。

§15.24 条件演算子?:(Java言語仕様 第2版)

仕様が変更されたのは、主にジェネリクスとオートボクシングに対応するためでしたが、その副作用で今回の例のような書き方も可能になったようです。

*1:lub は least upper bound(最小の上界)の略

*2:メソッド起動式 - 実引数に基づく型引数の推論

*3:Java のソースバージョンを 1.4 にしてコンパイルすると、上記の例はエラーになります。