名单<名单<? super =“”string =“”>无法按预期工作</list <?>

时间:2012-11-08 13:29:20

标签: java generics

List<Object>分配给List<? super String>可以正常工作。

List<List<Object>>分配给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's answer思考几个小时。所以我会在这里稍微扩展一下。也许这会帮助别人。

假设可以将List<List<CharSequence>>分配给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 points out,这是泛型协方差,与List<String>无法分配给List<Object>相同。使用List<? extends List<? super String>>代码实际上会编译,因为? extends String会阻止List.add()调用。

3 个答案:

答案 0 :(得分:7)

因为List<Object>List<? super String>不同。 List<? super String>包含一个您不知道的特定类型的对象,但它们是String或String的超类或超级接口。而List<Object>是一个可以容纳任何类型对象的List。

假设? 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?

答案 1 :(得分:4)

您必须将方法takeListOfListSuperString更改为

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

原因是协方差。内部类型List<? super String>必须完全匹配,而List<String>不是这种情况。解决方法是使用另一个通配符告诉Java组合的内部类型也应该是协变的。

答案 2 :(得分: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列表,即CharSequenceObject

但是我们分配的对象是ArrayList的{​​{1}}个,可以接受任何类和每个类。

因此两个列表都不同,java在编译时显示不同。