ジェネリックで使用?
する理由を誰かが説明できますか?Collection
例として:
List<? extends Number> numberlist;
List<? super Integer> numberlist;
ジェネリックで使用?
する理由を誰かが説明できますか?Collection
例として:
List<? extends Number> numberlist;
List<? super Integer> numberlist;
ワイルドカードは、コレクションの使用方法に制限を導入します。
たとえば、List<? extends Number>
を使用すると、リストに新しい要素を追加できません。これは、リストがのある種のサブタイプであるNumber
ということだけを知っているためですが、実際のサブタイプが何であるかはわかりません(つまり、何を追加するかをどうやって知ることができますか?)。たとえば、次のコードを考えてみましょう。
public void doSomethingWith(List<? extends Number> numbers) {
numbers.add(Integer.valueOf(0)); // Won't compile
}
これらのメソッド呼び出しは両方とも合法であるため、これはコンパイルされません。
doSomethingWith(new ArrayList<Integer>());
doSomethingWith(new ArrayList<Double>());
あなたができることは、リストから要素を読み取ることです:
// This will all compile
public void doSomethingWith(List<? extends Number> numbers) {
for (Number number : numbers) {
// Do something with number
}
// OR
Number number = numbers.get(0);
// OR
Number number = numbers.remove(0);
}
のようなメソッドを呼び出すと、get
ある種のが返されます。これNumber
は、のおかげで事実としてわかっているので、? extends Number
読み取りの目的でそのように扱うことができます。
一方、List<? super Integer>
は正反対の結果になります。リストから読み取ることはできなくなりましたが、書き込むことはできます。何であれ?
、それは間違いなくのスーパークラスになることを私は知っているInteger
ので、リストの具体的なタイプは間違いなく値を受け入れInteger
ます。例えば:
public void doSomethingWith(List<? super Integer> integers) {
integers.add(Integer.valueOf(0));
}
そのコードは完全に合法です。ただし、リストから読み取りたい場合は、これを行う唯一の方法は、Object
キャストが必要なため(具体的なタイプを知っている必要があるため)を使用することです。
for (Object obj : integers)
// OR
Object obj = integers.get(0);
// OR
Object obj = integers.remove(0);
本当に起こっていること
これが実際に起こっていることです。を指定すると、パラメータとして要素を? extends Number
受け取るメソッドを使用できなくなります。実際、EclipseでCtrl + Spaceを使用してコードをオートコンプリートしようとすると、メソッドなどのパラメーターのタイプとしてList<? extends Number>
表示されます。一方、要素を返すすべてのメソッドは、少なくともある種のを返すことが保証されていますが、実際にどのサブクラスであるかは正確にはわかりません。null
add
Number
Number
を指定すると、パラメータとして要素を受け取る? super Integer
メソッドを作成し、Integer
それらが値(およびのサブクラスも)を受け入れることを保証しますInteger
。add
これにより、型を受け入れることがわかっているので、のようなメソッドを呼び出すことができますInteger
。一方、要素を返すすべてのメソッドは何かを返すことが保証されていますが、何を返すかはわかりません。したがって、要素を返すすべてのメソッドは、を返すことだけが保証されていObject
ます。
PECSは、これを覚えておくための優れた頭字語です。これは、「P roducer E xtends、ConsumerSupers 」を意味します。これは、リストに何かを提供したい場合、それはプロデューサーであり、を使用する必要があることを意味します。あなたのリストがあなたからのものを受け入れることを望むなら、それは消費者なので、あなたはを使用します。詳細については、この回答を参照してください。extends
super
しかし、境界のないワイルドカードがある場合はどうなりますか?
それは両方を行います!<?>
ジェネリック型を引数として取るメソッドを呼び出さないように制限し、ジェネリック型を返すすべてのメソッドがを返すようにしますObject
。これは、タイプが何であるかがわからないためです。たとえば、これらの割り当てはすべてList<?>
合法です。
List<?> list;
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<MyClass>();
等々。
ワイルドカードとextendsとsuperの差分を学習しているときは、 PECSを覚えておいてください。このルールには、覚えておくのが非常に簡単なすべてが含まれています。
そのワイルドカード。?numberを継承するクラス、またはIntegerクラスのスーパークラスであるクラスが機能することを意味します。お役に立てれば。:)
?
ジェネリックを使用しながらワイルドカードを定義するために使用されます。
この例のステートメントは、Listが任意のタイプのオブジェクトを受け入れることを示していますNumber
?
すべてのクラスを意味するので
? extends MyClass
MyClassまたはMyClass自体のサブクラスを意味します。
これが私が言うことです:
List<? extends Number> numberlist; //Any class that is extended from Number class, for example Integer, BigInt, ... may come
List<? super Integer> numberlist; //Any class that Integer class is extended from. Here for example Number may come
なぜなら:
Integer extends Number{
}
List<? extends Number>
両方ともList<Number>
、たとえば整数を追加List<Number>
できますが、次のようになります。整数やその他の「数値」を入力できます。List<? extends Number>
そこに入れることができる具体的なruntimetypeは1つだけです。整数であっても、数値でもある別の型を追加することはできません。