質問
JLSが話していることに気づきました 5.1.10キャプチャコンバージョン, 、しかし、私は彼らが何であるかを理解していません。
誰かが私にそれらを説明しますか/例を挙げてもいいですか?
解決
キャプチャコンバージョンは、(ジェネリックで)ワイルドカードを作成するように設計されています。 ?
使える。
次のクラスがあるとします。
public interface Test<T> {
public void shout(T whatever);
public T repeatPreviousShout();
}
そして、私たちが持っている私たちのコードのどこかに、
public static void instantTest(Test<?> test) {
System.out.println(test.repeatPreviousShout());
}
なぜなら test
生ではありません Test
それ以来 repeatPreviousShout()
「後知恵」では、a ?
, 、コンパイラは、aがあることを知っています T
これは、のタイプパラメーターとして機能します Test
。これ T
いくつかの未知のためです T
したがって、コンパイラは未知のタイプを消去します(ワイルドカードの場合、それは Object
)、したがって repeatPreviousShout()
andを返します Object
.
しかし、もし持っていたら、
public static void instantTest2(Test<?> test) {
test.shout(test.repeatPreviousShout());
}
コンパイラは私たちに次のようなもののエラーを与えます Test<capture#xxx of ?> cannot be applied
(どこ xxx
数字です 337
).
これは、コンパイラがタイプの安全チェックを実行しようとしているためです shout()
しかし、ワイルドカードを受け取ったので、何がわかりません T
表現するため、呼ばれるプレースホルダーが作成されます の捕獲.
から ここに(Java理論と実践:ジェネリックでワイルドになる、パート1), 、それは明らかに述べています:
キャプチャコンバージョンは、コンパイラがキャプチャされたワイルドカードのプレースホルダータイプ名を製造できるようにするため、タイプの推論はそれがそのタイプであると推測できます。
これがあなたに役立つことを願っています。
他のヒント
ワイルドカードタイプの引数を含むパラメーター化されたタイプは、実際にはユニオンタイプです。例えば
List<? extends Number> = Union{ List<S> | S <: Number }
2つのケースでは、使用する代わりに List<? extends Number>
, 、Javaはキャプチャされたバージョンを使用します List<S>
, 、ここで、Sは上限を伴うばかりの作成されたタイプ変数です Number
.
(1) http://java.sun.com/docs/books/jls/third_edition/html/expressions.html
式のタイプを絞り込みます。式のタイプがある場合 List<? extends Number>
, 、私たちはオブジェクトのランタイムタイプが実際に List<S>
いくつかのコンクリートタイプsの場合(S <: Number>
)。コンパイラは使用します List<S>
代わりに、より正確なタイプ分析を実行します。
キャプチャ変換は各式に個別に適用されます。これはいくつかの愚かな結果につながります:
<T> void test1(List<T> a){}
<T> void test2(List<T> a, List<T> b){}
List<?> x = ...;
test1(x); // ok
test2(x, x); // error
(2) http://java.sun.com/docs/books/jls/third_edition/html/typesvalues.html#4.10.2
サブタイプチェックで A :< B
どこ A
ワイルドカードの議論が含まれます。例えば、
List<? extends Number> :< B
<=>
Union{ List<S> | S <: Number} :< B
<=>
List<S> :< B, for all S <: Number
したがって、実際には、キャプチャされたバージョンのタイプをチェックしています A