5

重複の可能性:
Java ArrayList of ? インターフェイスを拡張する

このコードがあります:

public static class B1 {}
public static class B2 extends B1 {}
public void fun() {
    List<? extends B1> l3 = new ArrayList<>();
    l3.add(new B2());
}

コンパイル エラー:

java: no suitable method found for add(Main.B2)
    method java.util.List.add(int,capture#1 of ? extends Main.B1) is not applicable
      (actual and formal argument lists differ in length)
    method java.util.List.add(capture#1 of ? extends Main.B1) is not applicable
      (actual argument Main.B2 cannot be converted to capture#1 of ? extends Main.B1 by method invocation conversion)

これは、 B1 から拡張される任意の型? extends B1を意味すると思います。タイプ B2 は B1 から拡張されているようですが、なぜこのタイプのオブジェクトをリストに追加できないのですか? また、追加できるようにする方法を教えてください。

4

5 に答える 5

9

これは、 B1 から拡張される任意の型? extends B1を意味すると思います。

いいえ。「B1 から拡張された特定の未知の型」を意味します。特定の型が不明であるため、コンパイラはそれを強制できないため、次のような操作は機能addしません。*

ワイルドカードに関するチュートリアルを参照してください。

追加できるようにするにはどうすればよいですか?

基本的に、これにはワイルドカードを使用しないでください。おそらくこれが必要です:

List<B1> l3 = new ArrayList<B1>();


*まあ、それらは機能しますが、null(および他のいくつかのケースについては、以下の@Markoのコメントを参照してください)。

于 2013-01-06T12:33:54.777 に答える
2

? extends B1意味:一部の型は B1 であるか、B1 を拡張していますが、どの型かはわかりません。したがって、リストは a List<B1>、または a List<B2>、またはa である可能性がありますList<B3>(B3 も B1 を拡張すると仮定します)。また、 B2 を a に追加したくないList<B3>ため、コンパイラはそれを禁止します。

おそらく、 が必要ですList<B1>

于 2013-01-06T12:35:00.643 に答える
1

B1したがって、私が推測するタイプの要素のリストが必要です。のすべての子は、次のようB1に のリストに保存できます。B1

public static class B1 {}
public static class B2 extends B1 {}
public void fun() {
    List<B1> l3 = new ArrayList<>();
    l3.add(new B2());
}
于 2013-01-06T12:34:44.717 に答える
0

同じインターフェイスを実装する B1 と B2 を作成し (空にすることもできます)、代わりにリスト <B> を宣言します。問題なくメンバーを追加および削除できます。

直接継承の主な問題は、次のように要約できます。

class B1 {};
class B2 extends B1{};

ArrayList<B2> list;

addMembers(list); // Error here

void addMembers(ArrayList<B1> list) {
  list.add(new B1());
}

ここで、B2 のリストを宣言し、B1 のリストを期待するメソッドにパラメーターとして渡します。各 B2 は B1 でもあるため、直感的にこれが機能するはずです。しかし今、このメソッドでは、渡されたリストに B1 も追加することが合法になります。メソッドが戻ると、宣言によって許可されていないメンバー B1 を含むコレクションが壊れます。

これを防ぐために、コンパイラはaddMembers「互換性のある継承された型」のコレクションで呼び出すことを許可しません。これは、提案されているインターフェイスを使用することで簡単に回避できる非常に厄介な制限であることがわかりました。ワイルドカードを使用してこれを正しく行うのはかなり複雑です。あなたはただ書くことができると思います? extends B1か?

void test() {
    ArrayList<? extends B1> list = new ArrayList();
    list.add(new B1()); // Error here
    list.add(new B2()); // Error here
    test2(list);
}

void test2(ArrayList<? extends B1> list) {
    list.add(new B1()); // Error here, the collection is read only.
}

これは、これらのワイルドカードは、関連する苦痛に見合うものではありません。ArrayList<? extends java.lang.Object> また、またはを書くこともできArrayList< ? > ますが、役に立ちません。そのような宣言は、コレクションを読み取り専用にします。

したがって、私は、より良いと思います

interface B {};
class B1 implements B {};
class B2 extends B1 implements B {};  

ArrayList<B> list = new ArrayList<B>();
list.add(new B1());
list.add(new B2());
test2(list);

void test2(ArrayList<B> list) {
    list.add(new B1());
}
于 2013-01-06T12:35:30.463 に答える
0

この質問はすでに回答されていますが、ここに何か価値のあるものを追加したいと思います。

List<B1> l3 = new ArrayList<B1>();

そのとおりです。ただし、ロジックを理解するには、エラーが発生しない以下も試してください。

public void fun() {
    List<? extends B1> l3 = new ArrayList<>();
    List list1= new ArrayList();
    list1.add(Element1 extending B1);
    list1.add(Element2 extending B1);
    l3=list1;
}

 or you can also try
public void fun() {
        List<? extends B1> l3 = new ArrayList<>();
        List<B1> list1= new ArrayList();
        list1.add(B1 element);
        l3=list1;
    }

したがって、以下のステートメントは一種の真ですが、メソッドの追加ではなく割り当て用です。add 操作を一言で言えば、本当に不明な型 (null など) である必要がありますが、

? extends B1 は、B1 から拡張された任意の型を意味します。

于 2013-01-06T14:21:45.217 に答える