次の 2 つのことを調べる必要があります。
- 署名でのワイルドカードの意味
void doStuff(Foo<? super Bar> foo)
- メソッド本体内のワイルドカードの意味
Java には、 と の間のサブタイプの関係を決定する非常に単純なルールが 1 つしかFoo<A>
ありませんFoo<B>
。none は other のサブタイプです。ジェネリック型は不変であると私たちは言います。Java 設計者がこのようにしたという理由があるとしても、あなたの観点からは、それは恣意的な決定です。
私たちを混乱させるのは山かっこです、かわいそうな開発者: 私たちはそれを受け入れることに何の問題もFooBar
ありFooQoo
ません。しかし、何らかの理由で、それを信じる必要がFoo<Qoo>
ありFoo<Bar>
ます。いいえ、そうではありません。
AとBがどのように関係していても関係X<A>
ありX<B>
ません。
AとBがどのように関係していても関係X<A>
ありX<B>
ません。
AとBがどのように関係していても関係X<A>
ありX<B>
ません。
上記のことを確信したら、次のスニペットを観察してください。
List<Double> doubles = ...;
List<Integer> integers = ...;
Number firstDouble = doubles.get(0);
Number firstInteger = integers.get(0);
get(0)
両方のリストを呼び出すと、Number 互換のオブジェクトが得られます。get()
の呼び出しを次のようなメソッドに入れたいと思うかもしれgetFirstOfList(list)
ませんが、まったく関係のない 2 つの型を受け入れるため、そのようなメソッドは存在できないことを学びました。
ここでワイルドカードの出番です!get()
a List<Number>
、 a List<Integer>
、 a (など)を呼び出すとNumber 互換オブジェクト (つまり、そのサブタイプList<Double>
) が返されるので、これを言語レベルで表現する方法が必要です。Java 設計者は、次のように機能するワイルドカードを提供してくれました。Number
public void doStuff(List<? extends Number> arg);
次の無限リストを宣言するのと同じ効果があります。
public void doStuff(List<Number> arg);
public void doStuff(List<Integer> arg);
public void doStuff(List<Double> arg);
public void doStuff(List<Float> arg);
public void doStuff(List<BigDecimal> arg);
...
ワイルドカードのデバイスがなければ、サポートされているリスト タイプごとに 1 つのメソッドを記述する必要があります (これは Java では違法ですが、それは別の話です)。
この例で使用したワイルドカードには、キーワードで識別される上限があります。extends
代わりに、貼り付けたスニペットは、メソッド シグネチャで下限super
のワイルドカードを採用しています ( )。実際には、次のような理由でいくつかのエラーが含まれている可能性があります。
List<Integer>
to を渡すことはできませんdoStuff()
Object
からのみ取得できますlist.get(index)
署名は
void doStuff(List<? super Number> arg);
は有限リストを表します:
void doStuff(List<Number> arg);
void doStuff(List<Object> arg);
Number
好きなものを に入れることができますが、そこからList<? super Number>
しか入れられませんget()
Object
。