1

将 a 分配List<Object>给 aList<? super String>工作正常。

将 a 分配List<List<Object>>给 aList<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 的答案几个小时。所以我会在这里稍微扩展一下。也许这会帮助别人。

假设将 a 分配List<List<CharSequence>>给 aList<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 指出的那样,这是泛型协方差,与List<String>不可分配给相同List<Object>。并且使用List<? extends List<? super String>>代码实际上会编译,因为? extends String阻止了List.add()调用。

4

3 回答 3

7

因为 a和 aList<Object>不是一回事List<? super String>。AList<? super String>包含一种特定类型的对象,您不知道,但它是 String 或 String 的超类或超接口。而 aList<Object>是一个可以容纳任何类型对象的列表。

假设? super StringCharSequence。您会觉得以下编译正常吗?

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>>String表示是ieCharSequence或超类的列表列表Object

但是我们分配的对象说ArrayListsList可以接受任何任何类和每个类。

所以这两个列表都是不同的,java 在编译时显示了这个不同。

于 2012-11-08T14:13:12.297 回答