对于以下代码示例:
public static class Abc<X> { }
public static class Def<Y> { }
public static class Ghi<Z> { }
public void doThis() {
List<?> listOne;
List<Abc<?>> listTwo;
List<Abc<Def<?>>> listThree;
List<Abc<Def<Ghi<?>>>> listFour;
List<Abc<Def<Ghi<String>>>> listFive;
Abc<Def<Ghi<String>>> abcdef;
abcdef = new Abc<Def<Ghi<String>>>();
listOne.add(abcdef); // line 1
listTwo.add(abcdef); // line 2
listThree.add(abcdef); // line 3
listFour.add(abcdef); // line 4
listFive.add(abcdef); // line 5
}
第1,3和4行不编译:
(第1行)
The method add(capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
(第3行)
The method add(Abc<Def<?>>) in the type List<Abc<Def<?>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
(第4行)
The method add(Abc<Def<Ghi<?>>>) in the type List<Abc<Def<Ghi<?>>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
然而,第2行和第5行编译。
任何人都可以解释为什么第1,3和4行不是合法的任务?如果不能在那些行上以这种方式使用通配符参数,那么为什么第2行的赋值是合法的?
listOne.add(abcdef)
(第1行)无效,因为List<?>
代表某种未知特定类型的列表。例如,它可能是一个List<String>
,所以我们不想添加任何不是String
的东西。编译器错误发生是因为Abc<Def<Ghi<String>>>
无法分配给?
。
listTwo.add(abcdef)
(第2行)是有效的,因为List<Abc<?>>
代表任何类型的Abc
s列表。这是正确的 - 嵌套通配符与顶级通配符的不同之处在于它们代表任何类型而不是某些特定类型(换句话说,嵌套通配符不是capture)。编译器允许它,因为Abc<Def<Ghi<String>>>
可以赋值给Abc<?>
。有关嵌套通配符的更多讨论,请参阅此文章:Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
listThree.add(abcdef)
(第3行)无效,因为List<Abc<Def<?>>>
代表任何类型的Abc
s的Def
s列表。泛型不是协变的,所以Abc<Def<Ghi<String>>>
不能赋予Abc<Def<?>>
,即使Def<Ghi<String>>
可以赋予Def<?>
。由于同样的原因,List<Integer>
不能转让给List<Number>
。有关进一步说明,请参阅此帖子:Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
listFour.add(abcdef)
(第4行)因同样的原因无效 - Abc<Def<Ghi<String>>>
不能转让给Abc<Def<Ghi<?>>>
。
listFive.add(abcdef)
(第5行)是有效的,因为泛型类型完全匹配 - Abc<Def<Ghi<String>>>
显然可以赋予Abc<Def<Ghi<String>>>
。