リストデータ構造に追加するにはどうすればよいですか ? 質問する

リストデータ構造に追加するにはどうすればよいですか ? 質問する

次のように宣言されたリストがあります:

 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)

ベストアンサー1

申し訳ありませんが、それはできません。

のワイルドカード宣言は、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>
  • は を指している可能性があるDoubleため、を追加することはできません。foo3List<Integer>
  • は を指している可能性があるNumberため、を追加することはできません。foo3List<Integer>

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

逆のロジックは に適用されます。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

Number特定の型 T (例) を から読み取ることはできません。実際に指しているのList<? super T>が の種類であるかを保証できないためです。唯一の「保証」は、指しているリストの整合性を侵害することなく、型(または の任意のサブクラス)Listの値を追加できることです。TT


この完璧な例は、次のシグネチャですCollections.copy():

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

リストsrc宣言で を使用するextendsと、関連するリスト型のファミリーから任意のリストを渡すことができ、それでも T 型または T のサブクラスの値が生成されます。ただし、リストに追加することはできませんsrc

リストdest宣言を使用するとsuper、関連するリスト型のファミリーから任意のリストを渡して、特定の型Tの値をそのリストに書き込むことができることが保証されます。ただし、次の値を読み取ることは保証されません。特定のリストから読み取る場合は T と入力します。

ジェネリック ワイルドカードのおかげで、次の呼び出しを 1 つのメソッドで実行できるようになりました。

// 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>());

Consider this confusing and very wide code to exercise your brain. The commented out lines are illegal and the reason why is stated to the extreme right of the line (need to scroll to see some of them):

  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>

おすすめ記事