4

一般的なリストを返すメソッドに問題があります。コードは基本的に次のとおりです。

public class MyClass{
    private List<MyListElement> myList = new ArrayList<MyListElement>();

    public <E> List<E> getGenericList(){
        return new ArrayList<E>();
    }

    public void thisWorks(){
        List<MyListElement> newList = getGenericList();
        myList.addAll(newList);
    }

    public void thisDoesntWork(){
        myList.addAll(getGenericList());
    }

    public void thisDoesntWorkEither(){
        for(MyListElement elem : getGenericList()){
            fiddle();
        }
    }
}

この方法がうまくいかないのはなぜですか? (常に実用的とは限らない方法thisDoesntWork()以外で) 回避する方法はありますか?thisWorks()

4

4 に答える 4

7

<E>コンパイラは、 のジェネリック メソッドgetGenericList()の型パラメーターに選択する型を推測できませんthisDoesntWork()

この場合、型引数の Type を明示的に指定する必要があります。<MyListElement>getGenericList()

または、署名を変更して引数getGenericList()を受け入れることもできます。次に、 との両方でClass<E>呼び出します。確かに、それはもう少し冗長ですが、メソッドのクライアントにとっては間違いなくより直感的です。getGenericList(MyListElement.class)thisWorks()thisDoesntWork()

原則として、ジェネリック メソッドの型引数をそのメソッドの引数から推測できるようにします。

于 2012-12-17T21:26:11.073 に答える
3

ジェネリック メソッドへの型引数は<E> getGenericsList()、呼び出し時に渡すことができます。

this.<String>getGenericsList()

それ以外の場合、コンパイラはコンテキストから推測するために最善を尽くします。返されたオブジェクトを参照に割り当てると、コンパイラは型引数List<String>として渡されたと推測します。String

List APIが与えられた場合:

List<E> {
  void addAll(Collection<? extends E> c);
}

コンパイラは正しい型を推測できないようです。正直なところ、これが十分に賢くないためなのか、それとも設計上責任を負いたくないからなのかはわかりません。

問題がワイルドカードであるかどうか、またはaddAll()パラメーター化された型から型引数を推測できないかどうかを確認するテストも行いましたが、何も機能していないようです:

public class GenericsList {

    public static void main(String[] args) {
        // same signature as Java API
        List<String> base = new List<String>();
        base.addAll(GenericsList.getList()); // ERROR!

        // addAll() doesn't use a wildcard
        List2<String> base2 = new List2<String>();
        base2.addAll(getList2()); // ERROR!

        // what about a generic method?
        addAll(base, getList()); // ERROR!
    }

    static <E> List<E> getList() {
        return new List<E>();
    }

    static <E> void addAll(List<E> src, List<E> other) {}

    static <E> List2<E> getList2() {
        return new List2<E>();
    }

    static class List<E> {
        void addAll(List<? extends E> other) {}
    }

    static class List2<E> {
        void addAll(List2<E> other) {}
    }

}
于 2012-12-17T21:46:26.087 に答える
3

thisDoesntWork()次のように変更できます。

  public void thisDoesntWork(){ // well, it works now
      myList.addAll(this.<String>getGenericList());
  }

どの型getGenericList()を扱っているかをコンパイラに伝える必要があります。

于 2012-12-17T21:25:34.023 に答える
0

このコードはあなたのために働くでしょう。 getGenericList()返されるものを知っている必要があり、リストの種類と互換性がある必要があります。

getGenericList メソッドの意図を文字列型に結び付けて制限するため、他の人が提案するように、文字列またはその他にキャストする必要はありません。

public class MyClass{
    private List<MyListElement> myList = new ArrayList<MyListElement>();

    public <E extends MyListElement> List<E> getGenericList(){
        return new ArrayList<E>();
    }

    public void thisWorks(){
        List<MyListElement> newList = getGenericList();
        myList.addAll(newList);
    }

    public void thisDoesntWork(){
        myList.addAll(getGenericList());
    }

    public void thisDoesntWorkEither(){
        for(MyListElement elem : getGenericList()){
            fiddle();
        }
    }
}
于 2012-12-18T07:06:15.440 に答える