リストに追加するにはどうすればよいですか?Number>データ構造を拡張しますか?


153

私はこのように宣言されたリストを持っています:

 List<? extends Number> foo3 = new ArrayList<Integer>();

私はfoo3に3を追加しようとしました。ただし、次のようなエラーメッセージが表示されます。

The method add(capture#1-of ? extends Number) in the type List<capture#1-of ?
extends Number> is not applicable for the arguments (ExtendsNumber)

61
List<? extends Number>「すべてが拡張されるさまざまなタイプのオブジェクトのリスト」を意味しないことに注意してくださいNumber。「拡張する単一タイプのオブジェクトのリスト」を意味しますNumber
Pavel Minaev

1
PECSルール、プロデューサー拡張、コンシューマースーパーのチェックを強化します。stackoverflow.com/questions/2723397/…–
noego

回答:


303

すみませんが、できません。

のワイルドカード宣言はList<? extends Number> foo3、変数foo3が(特定のタイプの値ではなく)タイプのファミリーからの任意の値を保持できることを意味します。これは、これらのいずれも合法的な割り当てであることを意味します。

List<? extends Number> foo3 = new ArrayList<Number>;  // Number "extends" Number
List<? extends Number> foo3 = new ArrayList<Integer>; // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>;  // Double extends Number

したがって、これを考えると、どのタイプのオブジェクトを追加できますか?List foo3上記の考えられるArrayList割り当てのいずれかの後、合法になります。

  • を指している可能性があるIntegerため、を追加できません。foo3List<Double>
  • 追加できません Doublefoo3指しいる可能性がためList<Integer>
  • を指してNumberいるfoo3可能性があるため、を追加できませんList<Integer>

List<? extends T>どの種類のオブジェクトListが実際に指しているかを保証できないため、オブジェクトを追加できません。そのため、オブジェクトが許可されていることを保証できませんList。唯一の「保証」は、そこから読み取ることしかできず、Tまたはのサブクラスを取得することですT

逆の論理はsuper、たとえばに適用されList<? super T>ます。これらは合法です:

List<? super Number> foo3 = new ArrayList<Number>; // Number is a "super" of Number
List<? super Number> foo3 = new ArrayList<Object>; // Object is a "super" of Number

特定のタイプT(たとえばNumber)を読み取るList<? super T>ことはできませんList。これは、それが実際に指している種類を保証できないためです。あなたが持っている唯一の「保証」はあなたがタイプの値T(またはTは、ポイントされているリストの整合性に違反することなく)のです。


この完璧な例は、次の署名ですCollections.copy()

public static <T> void copy(List<? super T> dest,List<? extends T> src)

srcリスト宣言がどのように使用するかに注意してくださいextendsして、関連するリストタイプのファミリーから任意のリストを渡し、タイプTまたはTのサブクラスの値を生成できることを保証するください。ただし、srcリストに追加することはできません。

destリスト宣言が使用するsuper私は、関連するリストの種類の家族から任意のリストを渡すと、まだ私はそのリストに特定のタイプTの値を書き込むことができます保証することができるようにします。しかし、それはの値を読み取ることを保証することはできません、リストから読み取る場合特定の型Tの。

だから今、ジェネリックのワイルドカードのおかげで、私はその単一のメソッドでこれらの呼び出しのいずれかを行うことができます:

// copy(dest, src)
Collections.copy(new ArrayList<Number>(), new ArrayList<Number());
Collections.copy(new ArrayList<Number>(), new ArrayList<Integer());
Collections.copy(new ArrayList<Object>(), new ArrayList<Number>());
Collections.copy(new ArrayList<Object>(), new ArrayList<Double());

あなたの脳を動かすために、この紛らわしくて非常に広いコードを考えてください。コメント化された行は違法であり、その理由が行の右端に示されています(一部を表示するにはスクロールする必要があります):

  List<Number> listNumber_ListNumber  = new ArrayList<Number>();
//List<Number> listNumber_ListInteger = new ArrayList<Integer>();                    // error - can assign only exactly <Number>
//List<Number> listNumber_ListDouble  = new ArrayList<Double>();                     // error - can assign only exactly <Number>

  List<? extends Number> listExtendsNumber_ListNumber  = new ArrayList<Number>();
  List<? extends Number> listExtendsNumber_ListInteger = new ArrayList<Integer>();
  List<? extends Number> listExtendsNumber_ListDouble  = new ArrayList<Double>();

  List<? super Number> listSuperNumber_ListNumber  = new ArrayList<Number>();
//List<? super Number> listSuperNumber_ListInteger = new ArrayList<Integer>();      // error - Integer is not superclass of Number
//List<? super Number> listSuperNumber_ListDouble  = new ArrayList<Double>();       // error - Double is not superclass of Number


//List<Integer> listInteger_ListNumber  = new ArrayList<Number>();                  // error - can assign only exactly <Integer>
  List<Integer> listInteger_ListInteger = new ArrayList<Integer>();
//List<Integer> listInteger_ListDouble  = new ArrayList<Double>();                  // error - can assign only exactly <Integer>

//List<? extends Integer> listExtendsInteger_ListNumber  = new ArrayList<Number>(); // error - Number is not a subclass of Integer
  List<? extends Integer> listExtendsInteger_ListInteger = new ArrayList<Integer>();
//List<? extends Integer> listExtendsInteger_ListDouble  = new ArrayList<Double>(); // error - Double is not a subclass of Integer

  List<? super Integer> listSuperInteger_ListNumber  = new ArrayList<Number>();
  List<? super Integer> listSuperInteger_ListInteger = new ArrayList<Integer>();
//List<? super Integer> listSuperInteger_ListDouble  = new ArrayList<Double>();     // error - Double is not a superclass of Integer


  listNumber_ListNumber.add(3);             // ok - allowed to add Integer to exactly List<Number>

  // These next 3 are compile errors for the same reason:
  // You don't know what kind of List<T> is really
  // being referenced - it may not be able to hold an Integer.
  // You can't add anything (not Object, Number, Integer,
  // nor Double) to List<? extends Number>      
//listExtendsNumber_ListNumber.add(3);     // error - can't add Integer to *possible* List<Double>, even though it is really List<Number>
//listExtendsNumber_ListInteger.add(3);    // error - can't add Integer to *possible* List<Double>, even though it is really List<Integer>
//listExtendsNumber_ListDouble.add(3);     // error - can't add Integer to *possible* List<Double>, especially since it is really List<Double>

  listSuperNumber_ListNumber.add(3);       // ok - allowed to add Integer to List<Number> or List<Object>

  listInteger_ListInteger.add(3);          // ok - allowed to add Integer to exactly List<Integer> (duh)

  // This fails for same reason above - you can't
  // guarantee what kind of List the var is really
  // pointing to
//listExtendsInteger_ListInteger.add(3);   // error - can't add Integer to *possible* List<X> that is only allowed to hold X's

  listSuperInteger_ListNumber.add(3);      // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>
  listSuperInteger_ListInteger.add(3);     // ok - allowed to add Integer to List<Integer>, List<Number>, or List<Object>

11
`List <のような文を書くことがなぜ許可されるのですか?このリストに要素を追加できない場合、Number> foo3 = new ArrayList <Integer>(); `を拡張しますか?
Amit Kumar Gupta

7
@articlestack:リストを処理するのに役立つのは、追加だけではありません。リストにデータが入力されると、リストからの読み取りが役立つ場合があります。ジェネリックワイルドカードを使用すると、リストのファミリーで一般的に機能するコードを記述できます。たとえば、List <Integer>またはList <Double>の両方で機能します。たとえば、Collection.copy()の署名を見てください。src List引数用途extendsながら、SRCのリストから読み取るためのdest List引数の用途はsuperDESTリストに書き込むために。これはからコピーすることができます一つの方法ことができますList<Integer>List<Double>List<Number>かをList<Object>
バートF

バートF、コメントが遅くなってすみません。「T型(またはTのサブクラス)の値を追加するには」(またはTのスーパークラス)と読むべきですか?
Vortex

ええ、私もそれを見ました@Vortex正しいか、間違って読んだかわかりません。
Ungeheuer 2016年

1
@渦- or subclass of T正しいです。例えば、私は追加できないObject(のスーパークラスをNumberする)List<? super Number> foo3ため、foo3:のように割り当てられていることができるList<? super Number> foo3 = new ArrayList<Number>(のみ含むことができNumber、またはサブクラスのNumber)。 に割り当てることができるの<? super Number>タイプを指します。そこから追加または読み取ることができるもののタイプではありません。追加/削除できるものの種類は、に割り当て可能なあらゆる種類の追加/削除できるものでなければなりません。List<>foo3foo3List<>foo3
バートF

17

できません(安全でないキャストがない場合)。あなたはそれらからしか読むことができません。

問題は、リストがリストの正確な内容を知らないことです。これはNumberの任意のサブクラスのリストである可能性があるため、要素をそこに入れようとしたときに、要素が実際にリストに収まるかどうかはわかりません。

たとえば、リストはByteのリストである可能性があるため、それにを入れるとエラーFloatになります。


2

"リスト '<'?extends Number>は実際には上限ワイルドカードです!

上限のあるワイルドカードは、NumberまたはNumber自体を拡張するすべてのクラスを仮パラメーターの型として使用できることを示しています。問題は、JavaがListの型を本当に認識していないという事実に起因します。正確かつ一意のタイプである必要があります。それが役に立てば幸いです:)



1

ここで回答を読んでも、Pavel Minaevのコメントが見つかるまで、混乱していました。

リスト<?extends Number>は、「すべてがNumberを拡張するさまざまなタイプのオブジェクトのリスト」を意味しません。「Numberを拡張する単一タイプのオブジェクトのリスト」を意味します

この後、BertFの素晴らしい説明を理解することができました。リスト<?数>を拡張しますか?Number(Integer、Doubleなど)を拡張する任意の型であり、宣言(List <?extends Number> list)で明確化されていないため、addメソッドを使用する場合、入力が同じタイプのかどうか。タイプは何ですか?

したがって、List <?extends Number>は、構築時にのみ設定できます。

また、これに注意してください。テンプレートを使用しているときは、どの型をいじっているのかをコンパイラに伝えています。たとえばTはそのタイプを保持しますが、そうではありませんか?同じことをする

私は言わなければならない..これは説明する/学ぶための汚いものの一つです


-1

'Object'からリストを拡張する場合は、list.addを使用できます。list.getを使用する場合は、オブジェクトをオブジェクトにキャストするだけです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.