46

次のコードがコンパイルされない理由を知っている人はいますか? add() も addAll() も期待どおりに機能しません。「? extends」部分を削除するとすべてが機能しますが、Foo のサブクラスを追加できなくなります。

 List<? extends Foo> list1 = new ArrayList<Foo>();
 List<? extends Foo> list2 = new ArrayList<Foo>();

 /* Won't compile */
 list2.add( new Foo() ); //error 1
 list1.addAll(list2);    //error 2 

エラー 1:

IntelliJ は次のように述べています。

add(capture<? extends Foo>) in List cannot be applied to add(Foo)

コンパイラは次のように述べています。

cannot find symbol
symbol  : method addAll(java.util.List<capture#692 of ? extends Foo>)
location: interface java.util.List<capture#128 of ? extends Foo>

エラー 2:

IntelliJは私に与えます

addAll(java.util.Collection<? extends capture<? extends Foo>>) in List cannot be applied to addAll(java.util.List<capture<? extends Foo>>)

コンパイラはただ言うのに対し

cannot find symbol
symbol  : method addAll(java.util.List<capture#692 of ? extends Foo>)
location: interface java.util.List<capture#128 of ? extends Foo>
        list1.addAll(list2);
4

5 に答える 5

61

(ここでは、BarBazが両方とも のサブタイプであると仮定しますFoo。)

List<? extends Foo>Foo のサブタイプである何らかのタイプの要素のリストを意味しますが、どのタイプかはわかりません。そのようなリストの例は、 a ArrayList<Foo>、 a 、LinkedList<Bar>および aArrayList<Baz>です。

どのサブタイプが型パラメーターであるかがわからないため、オブジェクトをそこに入れることも、オブジェクトを入れることもできませFooん。しかし、型パラメーターが のサブタイプであることはまだわかっているので、既にリストにあるすべての要素 (およびリストから取得できる要素) はオブジェクトである必要があるため 、 および類似のものを使用できます。BarBazFooFooFoo f = list.get(0);

このようなリストは、リストから要素を削除するためにのみ使用でき、要素をまったく追加することはできません (nullただし、コンパイラが実際にこれを許可しているかどうかはわかりません)。

List<Foo>一方、 はオブジェクトである任意のオブジェクトを追加できます。FooおよびはBarBazサブタイプであり、およびオブジェクトはFooすべてオブジェクトであるため、追加することもできます。BarBazFoo

于 2011-03-23T16:31:24.183 に答える
29

PECS: Producer Extends、Consumer Super を思い出してください。

list2 に項目を追加しようとしているため、これはコンシューマであり、 として宣言できませんList<? extends Foo>。ただし、list2 を list1 に追加するときにも、list2 をプロデューサーとして使用しています。したがって、list2 はプロデューサとコンシューマの両方であり、List<Foo>.

純粋な消費者としての list1 は、List<? super Foo>.

于 2011-03-23T15:56:36.947 に答える
9

それらはエラーです。BarBazが拡張する 2 つの異なるタイプであることを考慮して、コードを変更してみましょうFoo

List<? extends Foo> list1 = new ArrayList<Bar>();
List<? extends Foo> list2 = new ArrayList<Baz>();

許可されていればlist1.add(new Foo())、Bar インスタンスを含むコレクションに Foo インスタンスを追加できます。これは最初のエラーを説明しています。

が許可されている場合list1.addAll(list2)、list2 内の Baz のすべてのインスタンスが、Bar インスタンスのみを含む list1 に追加されます。これは、2番目のエラーを説明しています。

于 2011-03-23T15:57:49.890 に答える
2

申し訳ありませんが、あなたの質問を誤解しているかもしれませんが、次のように仮定します。

public class Bar extends Foo{ }

このコード:

List<Foo> list2 = new ArrayList<Foo>()
list2.add( new Bar() );

私のためにエラーを生成しません。

したがって、ワイルドカードを削除すると、Foo のサブクラスを追加できます。

于 2011-03-23T15:58:28.407 に答える