这里要记住的关键是嵌套通配符不会捕获。
这意味着您期望顶级通配符的“正常”行为(即通配符代表一个特定的东西)不适用于嵌套通配符。相反,嵌套通配符代表 any 类型。
以这个声明为例:
List<?> l;
这意味着l 是一个特定 类型的List。很简单。
但是这个呢?
Collection<List<?>> c;
这不是一个特定类型的Lists 中的Collection。这是Lists 中的Collection,每个都是一个特定类型。
例如,您预计会发生这样的事情:
Collection<List<?>> c = new ArrayList<List<Long>>(); // Not valid, but pretend it is
c.add(new ArrayList<Long>()); // Valid
c.add(new ArrayList<Integer>()); // Invalid, because c is a Collection of Lists of Long
但是考虑一下:
List<?> l = new ArrayList<String>();
c.add(l); // Should this compile?
l 的类型与c 的类型参数完全匹配,对吧?那么即使l 不是List<Long>,您是否也不能将l 添加到c?
还要考虑这个:
c.iterator().next(); // Assume there is an element to return
这应该返回什么类型? iterator() 返回 Iterator<E>,next() 返回 E,这意味着...c.iterator().next() 返回 List<?>。这不是您期望的List<Long>。这是为什么呢?
因为嵌套通配符不捕获。这就是这里的关键区别。 List<?> 中的通配符不捕获单一类型“整体”。它为Collection中的每个元素捕获一个单一类型。
因此,这是完全有效的代码:
Collection<List<?>> odd = new ArrayList<List<?>>();
odd.add(new ArrayList<String>());
odd.add(new ArrayList<Long>());
List<?> l = odd.iterator().next();
// returns the ArrayList<String>, but because odd is parameterized with
// List<?> we can technically end up with a list of anything
记住这一点,让我们看看你的例子。
Collection<Pair<String,Long>> c1 = new ArrayList<Pair<String,Long>>();
Collection<Pair<String,Long>> c2 = c1;
直觉上没问题。类型完全匹配,因此c1 可分配给c2。
Collection<Pair<String,Long>> c1 = new ArrayList<Pair<String,Long>>();
Collection<Pair<String,?>> c3 = c1;
现在,让我们回顾一下。 Collection<Pair<String,?>> 不是 Pairs 和 Strings 的 Collection 和单个未知类型。这是Collection 的Pairs,每个都是一对String 和一些未知类型,它可能与集合中的另一对类型相同,也可能不同。所以这是有效的:
// Assume an appropriate object was assigned to c3
Pair<String, ?> p1 = new Pair<String, String>("Hello", "World");
Pair<String, ?> p2 = new Pair<String, List<String>>("Lorem", new ArrayList<>());
Pair<String, ?> p3 = new Pair<String, Map<String, Integer>>("Ispum", new HashMap<>());
c3.add(p1);
c3.add(p2);
c3.add(p3);
由于这对c3 有效,但对c1 无效,因此不允许将c1 分配给c3,因为它允许您将内容放入ArrayList<Pair<String, Long>>那不是Pair<String, Long>。
Collection<Pair<String,Long>> c1 = new ArrayList<Pair<String,Long>>();
Collection<? extends Pair<String,?>> c4 = c1;
现在,这有点棘手。顶层捕获一个扩展Pair<String, ?> 的特定 类型。因为通配符是特定类型的超类型(例如List<?> 是List<Integer> 的超类型),Pair<String, Long> 可以被? extends Pair<String, ?> 捕获,因为前者扩展了后者。因此,因为Pair<String, Long> 与? extends Pair<String, ?> 是赋值兼容的,所以赋值是有效的。
您可以从这里的各种答案中看出,有多种方法可以解释嵌套通配符的行为。我想要更直观的解释,我希望我做到了。