CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第1章 ラムダ式とは : 問題 12 : インターフェースのデフォルトメソッド追加の安全性

問題 12

インターフェースにメソッドを追加することは、デフォルトメソッドであれば問題ない(はず…)
インターフェースへのデフォルトメソッドの追加は、どれぐらい安全か?
Collectionインターフェースの新たなstreamメソッドのせいで、古いコードのコンパイルが失敗するシナリオを述べよ

解答

安全ではない。
具象クラスでstreamメソッドを定義している(アクセス修飾子に係わらず)と、コンパイルエラーになる。

例えば、独自のList<Integer>の具象クラスFooList

public class FooList extends AbstractList<Integer> {
    private final int size;
    public FooList(int size) {
        this.size = size;
    }
    public Integer get(int index) {
        return Integer.valueOf(index);
    }
    public int size() {
        return size;
    }
    // ここまでは List の機能を満たすためのコードで問題ない
    public void stream() {
        System.out.println("Called FooList#stream()");
    }
}

となっていた場合、Java 8 ではコンパイルエラーとなる。

さらに問題

バイナリ互換性についてはどうか?

解答

バイナリ互換性は保障される。

即ち、上のFooListJava 8 以前でコンパイルして、その Jar ファイルを Java 8 から参照することは可能である。

じゃあFooListstreamメソッドを呼ぶと何が起こるでしょう。

List<Integer> list = new FooList(10);
((FooList)list).stream();    // "Called FooList#stream()"
System.out.println("FooList の個数 : " + list.stream().count());  // "10個"

FooListにキャストするとFooList独自のメソッドが呼ばれ、 ListとしてみたときはListインターフェースのデフォルトメソッドが呼ばれる。

つまり、そのインスタンスの型を具象クラスとするか親のインターフェースにするかで動きが違ってくるということである。
これは、今までの Java にはなかった挙動だ。