List<? super T>
とList<? extends T>
の違いは何ですか?
私はList<? extends T>
を使用していましたが、それに要素を追加することはできませんlist.add(e)
、List<? super T>
はそうしています。
extends
ワイルドカード宣言のList<? extends Number> foo3
は、これらのいずれもが正当な割り当てであることを意味します。
List<? extends Number> foo3 = new ArrayList<Number>(); // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number
Reading - 上記の可能な割り当てを考えると、List foo3
からどのタイプのオブジェクトを読み込むことが保証されているのでしょうか。
foo3
に割り当てることができるリストには、Number
またはNumber
のサブクラスが含まれているため、Number
を読み取ることができます。foo3
がList<Double>
を指している可能性があるため、Integer
を読み取ることはできません。foo3
がList<Integer>
を指している可能性があるため、Double
を読み取ることはできません。 Writing - 上記の可能な代入を考えて、 all 上記の可能なArrayList
代入に合法となる、どのタイプのオブジェクトをList foo3
に追加できますか。
foo3
はList<Double>
を指す可能性があるため、Integer
を追加することはできません。foo3
がList<Integer>
を指す可能性があるため、Double
を追加することはできません。foo3
がList<Integer>
を指す可能性があるため、Number
を追加することはできません。List<? extends T>
にオブジェクトを追加することはできません。なぜなら、それが実際にどのような種類のList
を指しているのか保証できないため、そのList
内でそのオブジェクトが許可されることを保証できません。あなたはそこからしか読むことができず、あなたはT
またはT
のサブクラスを得るでしょう。
super
今List <? super T>
を考えてください。
ワイルドカード宣言のList<? super Integer> foo3
は、これらのいずれもが正当な割り当てであることを意味します。
List<? super Integer> foo3 = new ArrayList<Integer>(); // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
Reading - 上記の可能な割り当てを考えると、あなたがList foo3
から読んだときどのような種類のオブジェクトを受け取ることが保証されていますか:
foo3
がList<Number>
またはList<Object>
を指している可能性があるため、Integer
は保証されていません。foo3
がList<Object>
を指す可能性があるため、Number
は保証されません。Object
またはObject
のサブクラスのインスタンスを取得するということです(ただし、どのサブクラスかはわかりません)。 Writing - 上記の可能な代入を考えて、 all 上記の可能なArrayList
代入に合法となる、どのタイプのオブジェクトをList foo3
に追加できますか。
Integer
は上記のリストのいずれでも使用できるため、Integer
を追加できます。Integer
のサブクラスのインスタンスは上記のいずれのリストでも許可されているため、Integer
のサブクラスのインスタンスを追加できます。foo3
がArrayList<Integer>
を指す可能性があるため、Double
を追加することはできません。foo3
がArrayList<Integer>
を指す可能性があるため、Number
を追加することはできません。foo3
がArrayList<Integer>
を指す可能性があるため、Object
を追加することはできません。PECSを忘れないでください: "プロデューサーの拡張、スーパーコンシューマ" 。
"Producer Extends" - List
の値を生成するためにT
が必要な場合(リストからT
sを読みたい場合)、? extends T
で宣言する必要があります。 List<? extends Integer>
。しかし、あなたはこのリストに追加することはできません。
"Consumer Super" - List
の値を消費するためにT
が必要な場合(T
sをリストに書き込みたい場合)、? super T
で宣言する必要があります。 List<? super Integer>
。しかし、このリストからどんな種類のオブジェクトを読み取ることができるかについての保証はありません。
リストから読み書きする必要がある場合は、ワイルドカードを使用せずに正確に宣言する必要があります。 List<Integer>
。
注意 この例は、Java Generics FAQ からのものです。ソースリストsrc
(生成リスト)がextends
を使用し、宛先リストdest
(消費リスト)がsuper
を使用する方法に注意してください。
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}
この階層を想像してみてください
書くことで
List<? extends C2> list;
あなたはlist
が(例えば)ArrayList
のジェネリック型がC2
の7 subtypes のいずれかである(C2
が含まれる)型のオブジェクトを参照できると言っています:
new ArrayList<C2>();
、(C2またはサブタイプを格納できるオブジェクト)またはnew ArrayList<D1>();
、(D1またはサブタイプを格納できるオブジェクト)またはnew ArrayList<D2>();
、(D2またはサブタイプを格納できるオブジェクト)または...等々。 7つの異なるケース
1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
2) new ArrayList<D1>(): can store D1 E1 E2
3) new ArrayList<D2>(): can store D2 E3 E4
4) new ArrayList<E1>(): can store E1
5) new ArrayList<E2>(): can store E2
6) new ArrayList<E3>(): can store E3
7) new ArrayList<E4>(): can store E4
可能性のあるそれぞれのケースに対して、「格納可能な」タイプのセットがあります。
ご覧のとおり、すべての場合に共通のsafe typeはありません。
list.add(new C2(){});
かもしれないのでlist = new ArrayList<D1>();
はできませんlist.add(new D1(){});
かもしれないのでlist = new ArrayList<D2>();
はできません等々。
書くことで
List<? super C2> list;
あなたはlist
が(例えば)ArrayList
の総称型が7 スーパータイプ of C2
(C2
が含まれる)のいずれかであるオブジェクトを参照できると言っているのです。
new ArrayList<A1>();
、(A1またはサブタイプを格納できるオブジェクト)またはnew ArrayList<A2>();
、(A2またはサブタイプを格納できるオブジェクト)またはnew ArrayList<A3>();
、(A3またはサブタイプを格納できるオブジェクト)または...等々。 7つの異なるケース
1) new ArrayList<A1>(): can store A1 B1 B2 C1 C2 D1 D2 E1 E2 E3 E4
2) new ArrayList<A2>(): can store A2 B2 C1 C2 D1 D2 E1 E2 E3 E4
3) new ArrayList<A3>(): can store A3 B3 C2 C3 D1 D2 E1 E2 E3 E4
4) new ArrayList<A4>(): can store A4 B3 B4 C2 C3 D1 D2 E1 E2 E3 E4
5) new ArrayList<B2>(): can store B2 C1 C2 D1 D2 E1 E2 E3 E4
6) new ArrayList<B3>(): can store B3 C2 C3 D1 D2 E1 E2 E3 E4
7) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
可能性のあるそれぞれのケースに対して、「格納可能な」タイプのセットがあります。
ご覧のとおり、ここでは7つの安全な型があり、これらはすべての場合に共通です:C2
、D1
、D2
、E1
、E2
、E3
、E4
。
C2
が許可されているため、list.add(new C2(){});
を使用できます。D1
が許可されているため、list.add(new D1(){});
を使用できます。等々。お気づきのとおり、これらの型はC2
型から始まる階層に対応しています。
いくつかのテストを行いたい場合は、ここで完全な階層
interface A1{}
interface A2{}
interface A3{}
interface A4{}
interface B1 extends A1{}
interface B2 extends A1,A2{}
interface B3 extends A3,A4{}
interface B4 extends A4{}
interface C1 extends B2{}
interface C2 extends B2,B3{}
interface C3 extends B3{}
interface D1 extends C1,C2{}
interface D2 extends C2{}
interface E1 extends D1{}
interface E2 extends D1{}
interface E3 extends D2{}
interface E4 extends D2{}
@Bert Fからの回答が大好きですが、これが私の脳の見方です。
手にXがあります。 write私のXをリストにしたい場合、そのリストは、Xのリストか、Xを書き込むときにアップキャストできるもののリストのいずれかでなければなりませんスーパークラス X ...
List<? super X>
リストを取得して、そのリストからreadをXにしたい場合は、Xのリスト、またはXにアップキャストできるもののリスト(つまり、何でも)そのextends X
List<? extends X>
お役に立てれば。
Bert F's answer 私の理解に基づいて説明したい。
として3つのクラスがあるとしましょう。
public class Fruit{}
public class Melon extends Fruit{}
public class WaterMelon extends Melon{}
ここにあります
List<? extends Fruit> fruitExtendedList = …
//Says that I can be a list of any object as long as this object extends Fruit.
[Ok]をクリックして、fruitExtendedListから値を取得してみましょう。
Fruit fruit = fruitExtendedList.get(position)
//This is valid as it can only return Fruit or its subclass.
もう一度試してみましょう
Melon melon = fruitExtendedList.get(position)
//This is not valid because fruitExtendedList can be a list of Fruit only, it may not be
//list of Melon or WaterMelon and in Java we cannot assign sub class object to
//super class object reference without explicitly casting it.
同じことが当てはまります。
WaterMelon waterMelon = fruitExtendedList.get(position)
それでは、fruitExtendedListにオブジェクトを設定してみましょう。
フルーツオブジェクトを追加する
fruitExtendedList.add(new Fruit())
//This in not valid because as we know fruitExtendedList can be a list of any
//object as long as this object extends Fruit. So what if it was the list of
//WaterMelon or Melon you cannot add Fruit to the list of WaterMelon or Melon.
メロンオブジェクトを追加する
fruitExtendedList.add(new Melon())
//This would be valid if fruitExtendedList was the list of Fruit but it may
//not be, as it can also be the list of WaterMelon object. So, we see an invalid
//condition already.
最後にWaterMelonオブジェクトを追加してみましょう
fruitExtendedList.add(new WaterMelon())
//Ok, we got it now we can finally write to fruitExtendedList as WaterMelon
//can be added to the list of Fruit or Melon as any superclass reference can point
//to its subclass object.
しかし待つもし誰かが新しいタイプのLemonを作ることを決めた場合、引数としてSaltyLemonとすることができます
public class SaltyLemon extends Lemon{}
これでfruitExtendedListはFruit、Melon、WaterMelonまたはSaltyLemonのリストになります
だから、私たちの声明
fruitExtendedList.add(new WaterMelon())
どちらも無効です。
基本的に、fruitExtendedListには何も記述できないと言えます。
これはList<? extends Fruit>
を要約します
今見てみましょう
List<? super Melon> melonSuperList= …
//Says that I can be a list of anything as long as its object has super class of Melon.
では、melonSuperListから値を取得してみましょう。
Fruit fruit = melonSuperList.get(position)
//This is not valid as melonSuperList can be a list of Object as in Java all
//the object extends from Object class. So, Object can be super class of Melon and
//melonSuperList can be a list of Object type
同様にMelon、WaterMelonまたは他のどのオブジェクトも読むことができません。
しかし、Object型のインスタンスを読むことができることに注意してください。
Object myObject = melonSuperList.get(position)
//This is valid because Object cannot have any super class and above statement
//can return only Fruit, Melon, WaterMelon or Object they all can be referenced by
//Object type reference.
それでは、melonSuperListから値を設定してみましょう。
オブジェクト型オブジェクトの追加
melonSuperList.add(new Object())
//This is not valid as melonSuperList can be a list of Fruit or Melon.
//Note that Melon itself can be considered as super class of Melon.
フルーツタイプオブジェクトの追加
melonSuperList.add(new Fruit())
//This is also not valid as melonSuperList can be list of Melon
メロン型オブジェクトの追加
melonSuperList.add(new Melon())
//This is valid because melonSuperList can be list of Object, Fruit or Melon and in
//this entire list we can add Melon type object.
WaterMelon型オブジェクトの追加
melonSuperList.add(new WaterMelon())
//This is also valid because of same reason as adding Melon
要約すると、melonSuperListにMelonまたはそのサブクラスを追加して、オブジェクト型オブジェクトのみを読み取ることができます。
superは下限で、extendsは上限です。
http://download.Oracle.com/javase/tutorial/extra/generics/morefun.htmlによると :
解決策は、まだ見たことのない形式の境界ワイルドカードを使用することです。下限を持つワイルドカード。構文は?スーパーTは、Tのスーパータイプである未知のタイプを表します(またはT自体。スーパータイプの関係は再帰的であることを忘れないでください)。これは、これまで使用してきたワイルドカードの2つです。どこで使用しますか。 Tのサブタイプである未知のタイプを表すために、Tを拡張します。
違いを視覚化したいのですが。我々が持っていると仮定します。
class A { }
class B extends A { }
class C extends B { }
List<? extends T>
- 読み取りと割り当て
|-------------------------|-------------------|---------------------------------|
| wildcard | get | assign |
|-------------------------|-------------------|---------------------------------|
| List<? extends C> | A B C | List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends B> | A B | List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends A> | A | List<A> List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
List<? super T>
- 書き込みと代入
|-------------------------|-------------------|-------------------------------------------|
| wildcard | add | assign |
|-------------------------|-------------------|-------------------------------------------|
| List<? super C> | C | List<Object> List<A> List<B> List<C> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super B> | B C | List<Object> List<A> List<B> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super A> | A B C | List<Object> List<A> |
|-------------------------|-------------------|-------------------------------------------|
すべての場合において:
Object
を取得できます。null
を可変リストに追加できます。リストに項目を追加する:
リスト<? Xを拡張 - > はリストにnull
を除いて、何も追加することを許可しない。
リスト<? super X> - X(Xまたはそのサブタイプ)、またはnullのものをすべて追加できます。
リストからアイテムを取得する:
Object
型の変数にのみ割り当てることができます。いくつかの例:
List<? extends Number> list1 = new ArrayList<Integer>();
list1.add(null); //OK
Number n = list1.get(0); //OK
Serializable s = list1.get(0); //OK
Object o = list1.get(0); //OK
list1.add(2.3); //ERROR
list1.add(5); //ERROR
list1.add(new Object()); //ERROR
Integer i = list1.get(0); //ERROR
List<? super Number> list2 = new ArrayList<Number>();
list2.add(null); //OK
list2.add(2.3); //OK
list2.add(5); //OK
Object o = list2.get(0); //OK
list2.add(new Object()); //ERROR
Number n = list2.get(0); //ERROR
Serializable s = list2.get(0); //ERROR
Integer i = list2.get(0); //ERROR
extends を使うとコレクションからのみ取得できます。入れることはできません。また、 super はgetとputの両方を許可しますが、get中の戻り型は ?です。スーパーT 。
ここで最も紛らわしいことは、私たちが指定した型制限がどのようなものであっても、代入は一方向にしか機能しないということです。
baseClassInstance = derivedClassInstance;
Integer extends Number
とInteger
は<? extends Number>
として機能すると考えるかもしれませんが、コンパイラは<? extends Number> cannot be converted to Integer
(つまり、人間の言い方では、数値を拡張するものはすべて整数に変換できるのは間違っていると教えてくれます。 ):
class Holder<T> {
T v;
T get() { return v; }
void set(T n) { v=n; }
}
class A {
public static void main(String[]args) {
Holder<? extends Number> he = new Holder();
Holder<? super Number> hs = new Holder();
Integer i;
Number n;
Object o;
// Producer Super: always gives an error except
// when consumer expects just Object
i = hs.get(); // <? super Number> cannot be converted to Integer
n = hs.get(); // <? super Number> cannot be converted to Number
// <? super Number> cannot be converted to ... (but
// there is no class between Number and Object)
o = hs.get();
// Consumer Super
hs.set(i);
hs.set(n);
hs.set(o); // Object cannot be converted to <? super Number>
// Producer Extends
i = he.get(); // <? extends Number> cannot be converted to Integer
n = he.get();
o = he.get();
// Consumer Extends: always gives an error
he.set(i); // Integer cannot be converted to <? extends Number>
he.set(n); // Number cannot be converted to <? extends Number>
he.set(o); // Object cannot be converted to <? extends Number>
}
}
Integer
は任意のスーパークラスのNumber
に変換できるため、hs.set(i);
は問題ありません(Integer
がNumber
のスーパークラスであるためではありません)。
EDITはConsumer ExtendsとProducer Superについてのコメントを追加しました - それらはnothingとObject
を指定しているので意味がありません。 CEPSは役に立ちませんので、PECSを覚えておくことをお勧めします。
.add()
が'<?>'
、'<? extends>'
、そして部分的に'<? super>'
に制限されている理由を理解するために上記のすべての答えを調べることができます。
あなたがそれを覚えておきたいと思うなら、ここにそれのすべての結論があります、そして毎回答えを探りに行きたくはありません:
List<? extends A>
は、これがList
のすべてのA
およびA
のサブクラスを受け入れることを意味します。しかし、このリストには何も追加できません。 A
型のオブジェクトすらありません。
List<? super A>
は、これがA
のリストとA
のスーパークラスを受け入れることを意味します。 A
型のオブジェクトとそのサブクラスを追加できます。
拡張を使用し、super を使用する場合
ワイルドカードは、メソッドパラメータで最も役立ちます。それらはメソッドインターフェースに必要な柔軟性を可能にします。
拡張を使うときとスーパーバウンドを使うときを混同している人はよくいます。経験則は、原則です。パラメータ化されたコンテナから何かを取得したら、extendsを使用してください。
int totalFuel(List<? extends Vehicle> list) {
int total = 0;
for(Vehicle v : list) {
total += v.getFuel();
}
return total;}
メソッドtotalFuelはリストからVehiclesを取得し、燃料の量について質問し、合計を計算します。オブジェクトをパラメータ化されたコンテナに入れる場合は、superを使用してください。
int totalValue(Valuer<? super Vehicle> valuer) {
int total = 0;
for(Vehicle v : vehicles) {
total += valuer.evaluate(v);
}
return total;}
メソッドtotalValueはVehiclesをValuerに入れます。拡張範囲はsuperよりはるかに一般的であることを知っておくと便利です。
投票された回答には、さまざまな側面に関する詳細が含まれています。しかし、私はこれとは異なる方法で答えようとします。
考慮すべきことが2つあります。
List<? extends X> listvar;
ここでは、listvarに任意のXのリストまたはXのサブクラスのリストを代入することができます _を使用できます。
List<? extends Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Integer>();
List<? super X> listvar;
ここで、listvarには、任意のXのリストまたはXのスーパークラスのリストを代入することができます _を使用できます。
List<? super Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Object>();
`List<? extends X> listvar;`
この機能を使用して、メソッドの引数でリストを受け取り、type Xに対して任意の操作を実行できます(注:listからタイプXのオブジェクトのみを実行できます)。
`List<? super Number> listvar;
この機能を使用して、メソッドの引数でリストを受け取り、リストからタイプObjectのオブジェクトのみを実行できるようにタイプObjectに対して任意の操作を実行できます。 ただし、ここで追加のことは、タイプXのオブジェクトをリストに追加できることです。
一般的なワイルドカードは、2つの主なニーズをターゲットにしています。
総称コレクションからの読み取り総称コレクションへの挿入総称ワイルドカードを使用してコレクション(変数)を定義する方法は3つあります。これらは:
List<?> listUknown = new ArrayList<A>();
List<? extends A> listUknown = new ArrayList<A>();
List<? super A> listUknown = new ArrayList<A>();
List<?>
は未知の型に型付けされたリストを意味します。これはList<A>
、List<B>
、List<String>
などです。
List<? extends A>
は、class A
、またはsubclasses of A
のインスタンスであるオブジェクトのリストを意味します(例:BとC)。 List<? super A>
は、リストがA class
またはsuperclass of A
のいずれかに入力されることを意味します。
続きを読む: http://tutorials.jenkov.com/Java-generics/wildcards.html
|
v
リスト<? X> を拡張する は、任意の サブクラス
X
またはそれ自体X
のいずれかです。リスト<?スーパーX> ? は、 スーパークラス of
X
、またはそれ自体X
のいずれかです。
^
|
例、継承の順番はO> S> T> U> Vとします。
extendsキーワードの使用、
正しい:
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
不正確:
List<? extends T> Object = new List<S>();
List<? extends T> Object = new List<O>();
スーパーキーワード:
正しい:
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
不正確:
List<? super T> Object = new List<U>();
List<? super T> Object = new List<V>();
オブジェクトを追加します。List Object = new List();
Object.add(new T()); //error
しかし、なぜエラーですか?リストオブジェクトの初期化の可能性を見てみましょう
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
Object.add(new T())を使用した場合その場合にのみ正しいでしょう
List<? extends T> Object = new List<T>();
しかし、さらに2つの可能性があります。
リストオブジェクト= new List();リストオブジェクト= new List();上記の2つの可能性に(new T())を追加しようとすると、TがUとVの上位クラスであるため、エラーが発生します。 Tオブジェクト[(new T())]をU型とV型のListに追加します。上位クラスのオブジェクト(基本クラス)を下位クラスのオブジェクト(下位クラス)に渡すことはできません。
2つの可能性があるため、Javaは参照しているオブジェクトがわからないため、正しい可能性を使用してもエラーが発生します。List Objectにオブジェクトを追加することはできません。有効ではない可能性があるので。
オブジェクトを追加します。List Object = new List();
Object.add(new T()); // compiles fine without error
Object.add(new U()); // compiles fine without error
Object.add(new V()); // compiles fine without error
Object.add(new S()); // error
Object.add(new O()); // error
しかし、なぜ上記の2つでエラーが発生するのでしょうか。 Object.add(new T())を使うことができます。以下の可能性についてのみ
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
List Object = new List()でObject.add(new T())を使用しようとした場合。 List Object = new List()。これはエラーになります。これは、List object = new List()にT object [new T()]を追加できないためです。それはタイプUのオブジェクトだからです。 Tは基底クラスであり、Uはサブクラスであるため、Tオブジェクト[new T()]をUオブジェクトに追加することはできません。基本クラスをサブクラスに追加することはできません。そのため、エラーが発生します。他の場合も同様です。