1 は機能し、2 は機能しないのはなぜですか?
1:
public List<? extends Integer> l1;
public List<? extends Number> l2 = l1;
2:
public List<U> l1;
public List<S> l2 = l1;
//where U and S have been previously defined as: **S extends Number,U extends Integer**
ジェネリックは共変ではありません。例えば:
List<Integer> l1;
List<Number> l2;
l1 = l2; // incompatible types
l2 = l1; // also incompatible
ただし、ワイルドカード型は共分散を表現する方法を提供します。
List<? extends Integer> l1;
List<? extends Number> l2 = l1; //legal
l1
は、 または extendsList
である不明な型のとして表現されていInteger
ます。同様に、l2
isList
または extends の型ですNumber
。Integer
extends以来Number
、コンパイラはへの代入が問題ないことを知っていl1
ますl2
。
この状況は異なります。
<S extends Number, U extends Integer> void someMethod() {
List<U> l1;
List<S> l2 = l1; //incompatible types
}
S
およびは型パラメーターです。つまり、 (または型推論)U
の呼び出し元によっていくつかの特定の型引数が提供されます。これらの型引数は、ワイルドカード キャプチャのsomeMethod
ような具象型にすることができます。Integer
それらも境界付きですが、これは上記のような境界付きワイルドカードの使用とは異なります。型パラメーターは宣言時に制限されます。メソッド本体内では、変更されないと理解されています。たとえば、 と の両方S
が次の呼び出しによってU
解決されたとします。Integer
this.<Integer, Integer>someMethod();
この場合、メソッド本体は次のようになると想像できます。
List<Integer> l1;
List<Integer> l2 = l1; // okay why not?
これは合法ですが、たまたま運が良かっただけです。そうではない状況もたくさんあります。例えば:
this.<Double, Integer>someMethod();
ここで、メソッド本体を再考します。
List<Integer> l1;
List<Double> l2 = l1; // danger!
したがって、境界付きの型パラメーターは、境界付きのワイルドカードとは大きく異なるものであることがわかります。これにより、さまざまなジェネリック型を共変的に「スワップイン」できます。
List<Integer> l1;
List<Double> l2;
List<? extends Number> l3;
l3 = l1;
l3 = l2;
Integer
ところで:は拡張できません。クラスですInteger
。final
// l1 holds any subclass of Integer and, because Integer implements Number it is also a subclass of Number
public List<? extends Integer> l1;
// l1 (see above) implements Number so this is fine.
public List<? extends Number> l2 = l1;
// Using Integer here instead of your U because you cannot extend Integer - it is final.
public List<Integer> l3;
// Make S extend Number
static class S extends Number {
// Implementing the abstract methods of Number
}
// NOT valid because l4 must be a List of S not a list of ANY Number and l3 is a List<Integer> - no connection other than a commmon interface.
public List<S> l4 = l3;
1.1 では Integer を拡張する任意のクラスを、1.2 では Number を拡張する任意のクラスを意味します。Integer は Number のサブクラスであるため、最初のケースではエラーが発生しませんでした。しかし、2.1 は U だけを言っていて、2.2 では S だけを言っています。
public List<S> l2 = l1
l1 は S ではなく U 型であり、ジェネリックはそれ自身によるそのようなオブジェクト参照をサポートしていません。最初のケースで使用したように、ワイルド カードを使用する必要があります。
public List<? extends Number> l2 = l1;
あなたの問題を解決します..
1では、整数と数値のサブクラスをそれぞれ言っているからです。
しかし、2 番目に、U と S のジェネリックと言っていますが、このジェネリックは、Java OOP のサブクラス オブジェクトの概念を参照できるスーパーをサポートしていません。