ワイルドカードと捕捉変換

引き続き自分めも。

Eclipseでよく見かけるエラー。

これは疑似的には次のように解釈されてる。

ローカル変数の前に書いてある< ... >は、ローカル変数でジェネリック宣言しますよってことで。

private void test1(List<?> a, List<?> b) {
    <capture#2> capture#2 b_get = b.get(0);
    <capture#1> capture#1 a_add = b_get; // 型エラー
    a.add(a_add);
}

厳密にはメソッド起動変換*1を代入変換*2で表現してるから上記は多少おかしいのですが、本質はそこではないのでスルーします。

capture#1, 2は型変数とみなされて、それぞれこんな型。

型変数 上限境界 下限境界
capture#1 (a_add) Object null
capture#2 (b_get) Object null

"a_add = b_get"が失敗する理由は、capture#2(b_get)がcapture#1(a_add)のサブタイプでないためです。このサブタイピング関係は下記で規定してます。

...
The direct supertypes of a type variable (§4.4) are the types listed in its bound.
The direct supertypes of the null type are all reference types other than the null type itself.
In addition to the above rules, a type variable is a direct supertype of its lower bound.

4.10.2 Subtyping among Class and Interface Types

capture#kはa.getとかa.setやるたびに新しく発行されるので、a.set(a.get(0)) とかもだめです。a.setの引数型がcapture#x, a.getの戻り値型がcapture#yと評価されて別の型に。

適切な境界を指定してやれば動くようになる。

void test2(List<? super Number> a, List<? extends Number> b) {
    a.add(b.get(0));
}

これは疑似的にはこう解釈される。

void test2(List<? super Number> a, List<? extends Number> b) {
    <capture#2 extends Number> capture#2 b_get = b.get(0);
    <capture#1 super Number>   capture#1 a_add = b_get;
    a.add(a_add);
}
型変数 上限境界 下限境界
capture#1 (a_add) Number null
capture#2 (b_get) Object Number

で、型変数のサブタイプ関係を再掲すると、

...
The direct supertypes of a type variable (§4.4) are the types listed in its bound.
The direct supertypes of the null type are all reference types other than the null type itself.
In addition to the above rules, a type variable is a direct supertype of its lower bound.

4.10.2 Subtyping among Class and Interface Types

ということで "capture#2