6

ジェネリックで使用?する理由を誰かが説明できますか?Collection

例として:

 List<? extends Number> numberlist;
 List<? super Integer> numberlist;
4

7 に答える 7

29

ワイルドカードは、コレクションの使用方法に制限を導入します。

たとえば、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>表示されます。一方、要素を返すすべてのメソッドは、少なくともある種のを返すことが保証されていますが、実際にどのサブクラスであるかは正確にはわかりません。nulladdNumberNumber

を指定すると、パラメータとして要素を受け取る? super Integerメソッドを作成しIntegerそれらが値(およびのサブクラスも)を受け入れることを保証しますIntegeraddこれにより、型を受け入れることがわかっているので、のようなメソッドを呼び出すことができますInteger。一方、要素を返すすべてのメソッドは何かを返すことが保証されていますが、何を返すかはわかりません。したがって、要素を返すすべてのメソッドは、を返すことだけが保証されていObjectます。

PECSは、これを覚えておくための優れた頭字語です。これは、「P roducer E xtends、ConsumerSupers 」を意味します。これは、リストに何かを提供したい場合、それはプロデューサーであり、を使用する必要があることを意味します。あなたのリストがあなたからのものを受け入れることを望むなら、それは消費者なので、あなたはを使用します。詳細については、この回答を参照してください。extendssuper

しかし、境界のないワイルドカードがある場合はどうなりますか?

それは両方を行います!<?>ジェネリック型を引数として取るメソッドを呼び出さないように制限し、ジェネリック型を返すすべてのメソッドがを返すようにしますObject。これは、タイプが何であるかがわからないためです。たとえば、これらの割り当てはすべてList<?>合法です。

List<?> list;
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<MyClass>();

等々。

于 2012-09-26T15:33:46.590 に答える
2

ワイルドカードとextendssuperの差分を学習しているときは、 PECSを覚えておいてください。このルールには、覚えておくのが非常に簡単なすべてが含まれています。

于 2012-09-26T15:06:36.503 に答える
2

そのワイルドカード。?numberを継承するクラス、またはIntegerクラスのスーパークラスであるクラスが機能することを意味します。お役に立てれば。:)

于 2012-09-26T14:55:39.197 に答える
1

?ジェネリックを使用しながらワイルドカードを定義するために使用されます。

この例のステートメントは、Listが任意のタイプのオブジェクトを受け入れることを示していますNumber

于 2012-09-26T14:52:02.557 に答える
1

?すべてのクラスを意味するので

? extends MyClass

MyClassまたはMyClass自体のサブクラスを意味します。

于 2012-09-26T14:53:01.900 に答える
1

これが私が言うことです:

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{
}
于 2012-09-26T15:02:33.263 に答える
0

List<? extends Number>両方ともList<Number>、たとえば整数を追加List<Number>できますが、次のようになります。整数やその他の「数値」を入力できます。List<? extends Number>そこに入れることができる具体的なruntimetypeは1つだけです。整数であっても、数値でもある別の型を追加することはできません。

于 2012-09-26T15:06:49.773 に答える