将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()
调用。
答案 0 :(得分:7)
因为List<Object>
与List<? super String>
不同。 List<? super String>
包含一个您不知道的特定类型的对象,但它们是String或String的超类或超级接口。而List<Object>
是一个可以容纳任何类型对象的List。
假设? 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?
答案 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
列表,即CharSequence
或Object
但是我们分配的对象是ArrayList
的{{1}}个,可以接受任何类和每个类。
因此两个列表都不同,java在编译时显示不同。