web-dev-qa-db-ja.com

<の違いは何ですか? Foo>と<Foo>を拡張します

<Foo><? extends Foo>の違いについて誤解しているようです。私の理解から、もし

ArrayList<Foo> foos = new ArrayList<>();

これは、タイプFooのオブジェクトをこの配列リストに追加できることを示しています。 FooのサブクラスもFoo型なので、次のようにエラーなしで追加できます。

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

ここで、Bar extends Foo

ここで、foosを次のように定義したとしましょう

ArrayList<? extends Foo> foos = new ArrayList<>();

私の現在の理解では、これはsome unknown type that extends Fooを表すということです。これは、Fooのサブクラスであるすべてのオブジェクトをこのリストに追加できることを意味します。つまり、ArrayList<Foo>ArrayList<? extends Foo>の間に違いはありません。

これをテストするために、私は次のコードを書いてみました

ArrayList<? extends Foo> subFoos = new ArrayList<>();
subFoos.add(new Foo());
subFoos.add(new Bar());

しかし、次のコンパイルエラーが表示されました

no suitable method found for add(Foo)
method Java.util.Collection.add(capture#1 of ? extends Foo) is not applicable
(argument mismatch; Foo cannot be converted to capture#1 of ? extends Foo)

no suitable method found for add(Bar)
method Java.util.Collection.add(capture#2 of ? extends Bar) is not applicable
(argument mismatch; Bar cannot be converted to capture#2 of ? extends Bar)

現在の理解に基づいて、<? extends Foo>のリストにFooを追加できない理由がわかります。これは、それ自体のサブクラスではないためです。しかし、なぜBarをリストに追加できないのか知りたいです。

私の理解のどこに穴がありますか?

23
Zymus

あなたが自分で発見したように、ArrayList<? extends Foo> subFoos = new ArrayList<>();として宣言されたArrayListはあまり役に立ちません。

<? extends T>の有用性を確認するには、次のことを考慮してください。

List<Foo> collect( List<? extends Foo> a1, List<? extends Foo> a2 )
{
    List<Foo> collected = new ArrayList<>();
    collected.addAll( a1 );
    collected.addAll( a2 );
    return collected;
}

これは後で次のように使用できます。

List<Foo> foos = collect( new ArrayList<Foo>(), new ArrayList<Bar>() );

または次のように:

List<Foo> foos = collect( new ArrayList<Bar>(), new ArrayList<Foo>() );

collectメソッドが次のように宣言されている場合、上記のいずれも機能しないことに注意してください。

List<Foo> collect( List<Foo> a1, List<Foo> a2 )
15
Mike Nakis