1

List<Object>aを a に割り当てるとList<? super String>うまくいきます。

List<List<Object>>aに a を代入しList<List<? super String>>てもコンパイルされません。

コード

public class Main {
    public static void main(String[] args) {
        // works fine
        List<Object> listOfObject = new ArrayList<>();
        takeListSuperString(listOfObject);

        // doesn't compile
        List<List<String>> listOfListOfObject = new ArrayList<>();
        takeListOfListSuperString(listOfListOfObject);
    }

    static void takeListSuperString(List<? super String> listSuperString) {

    }

    static void takeListOfListSuperString(List<List<? super String>> listOfListSuperString) {

    }
}

質問

List<List<? super String>>と同じように動作しないのはなぜList<? super String>ですか?

また、このようなことを検索できる場所はありますか?

関連する質問はGenerics hell: hamcrest matcher as a method parameterです。しかし、そこにある答えは役に立ちません。

編集

最終的にそれを得る前に、JB Nizet の回答を数時間考えなければなりませんでした。というわけで、ここから少し拡大します。多分それは他の誰かを助けるでしょう。

List<List<CharSequence>>aへの a の代入が可能であると仮定するとList<List<? super String>>、次のコードがコンパイルされます。

// can only contain instances of CharSequence
List<List<CharSequence>> listOfListOfCharSequences = new ArrayList<>();

List<List<? super String>> listOfListSuperString = listOfListOfCharSequences;

// add a list of objects containing an Integer
List<Object> listOfObjects = new ArrayList<>();
listOfObjects.add(123);
listOfListSuperString.add(listOfObjects);

// Ups.. exception at runtime we are getting an Integer where we expect a CharSequence
CharSequence charSequence = listOfListOfCharSequences.get(0).get(0);

したがって、実行時の醜い例外を防ぐために許可されていません。

halex が指摘しているように、これは Generics 共分散であり、 a が に代入List<String>できないのと同じList<Object>です。そして、コードを使用すると、呼び出しが妨げList<? extends List<? super String>>られるため、実際にコンパイルされます。? extends StringList.add()

4

3 に答える 3

7

aList<Object>は a と同じではないからList<? super String>です。AList<? super String>は、あなたが知らない特定のタイプのオブジェクトを保持しますが、それは String または String のスーパークラスまたはスーパーインターフェースです。一方、 aList<Object>はあらゆる種類のオブジェクトを保持できるリストです。

だとし? super StringますCharSequence。以下がコンパイルされるのは正常だと思いますか?

List<List<Object>> listOfListOfObjects = new ArrayList<List<Object>>();
List<Object> listOfObjects = new ArrayList<Object>(); 
listOfObjects.add(new Integer());
listOfListOfObjects.add(listOfObjects);
List<List<CharSequence>> listOfListOfCharSequences = listOfListOfObjects; // WTF?
于 2012-11-08T13:38:49.467 に答える
4

takeListOfListSuperStringメソッドを次のように変更する必要があります

static void takeListOfListSuperString(List<? extends List<? super String>> ListOfListSuperString)

その理由は共分散です。内側の型List<? super String>は正確に一致する必要がありますが、 の場合はそうではありませんList<String>。回避策は、結合された内部型も共変である必要があることを Java に伝える別のワイルドカードを使用することです。

于 2012-11-08T13:42:10.793 に答える
0

上記の質問は異なります...次のように質問を理解できます。

List<? super String> a = new ArrayList<Object>();
List<List<? super String>> b = new ArrayList<List<Object>>();

List<List<? super String>> c = new ArrayList<List<? super String>>();

このコードでは、2行目はコンパイルされていません....では、なぜコンパイルされていないのでしょうか?

答え:

List<List<? super String>>StringieCharSequenceまたはのスーパークラスであるリストのリストを意味しますObject

しかし、私たちが割り当てているオブジェクトは、任意のクラスとすべてのクラスを受け入れることができる s についてArrayList述べています。List

したがって、両方のリストが異なり、Java はコンパイル時にこの違いを示します。

于 2012-11-08T14:13:12.297 に答える