Java Generics:使用嵌套通配符参数进行赋值

sum*_*tsu 12 java generics nested-generics type-parameter

对于以下代码示例:

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
}
Run Code Online (Sandbox Code Playgroud)

第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>>>)
Run Code Online (Sandbox Code Playgroud)

(第3行)

The method add(Abc<Def<?>>) in the type List<Abc<Def<?>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
Run Code Online (Sandbox Code Playgroud)

(第4行)

The method add(Abc<Def<Ghi<?>>>) in the type List<Abc<Def<Ghi<?>>>> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
Run Code Online (Sandbox Code Playgroud)

然而,第2行和第5行编译.

任何人都可以解释为什么第1,3和4行不是合法的任务?如果不能在那些行上以这种方式使用通配符参数,那么为什么第2行的赋值是合法的?

Pau*_*ora 11

listOne.add(abcdef)(第1行)无效,因为它List<?>代表某个未知特定类型的列表.例如,它可能是a List<String>,所以我们不想添加任何不是a的东西String.发生编译器错误,因为Abc<Def<Ghi<String>>>无法分配?.

listTwo.add(abcdef)(第2行)有效,因为它List<Abc<?>>代表任何类型Abcs 列表.这是正确的 - 嵌套通配符与顶级通配符的不同之处在于它们代表任何类型而不是某些特定类型(换句话说,嵌套通配符不会捕获).编译器允许它,因为可以赋值.有关嵌套通配符的进一步讨论,请参阅此文章:泛型方法上的多个通配符使Java编译器(和我!)非常混淆Abc<Def<Ghi<String>>>Abc<?>

listThree.add(abcdef)(第3行)无效,因为它List<Abc<Def<?>>>代表任何类型AbcDefs 列表.泛型不是协变的,因此即使可以赋值,也Abc<Def<Ghi<String>>>不能赋值.出于同样的原因,A 不能分配给a .有关进一步说明,请参阅此文章:List <Dog>是List <Animal>的子类吗?为什么Java的泛型不是隐式多态的?Abc<Def<?>>Def<Ghi<String>>Def<?>List<Integer>List<Number>

listFour.add(abcdef)(第4行)因同样的原因无效 - Abc<Def<Ghi<String>>>无法转让Abc<Def<Ghi<?>>>.

listFive.add(abcdef)(第5行)是有效的,因为泛型类型完全匹配 - Abc<Def<Ghi<String>>>显然可以赋值给Abc<Def<Ghi<String>>>.

  • 想要跟进,注意第3行和第4行的可赋值性问题可以通过将`List <Abc <Def <?>>> listThree`的声明改为`List <Abc <?来解决.将Def <?>>> listThree`和`List <Abc <Def <Ghi <?>>>>`扩展为`List <Abc <?扩展Def <?扩展Ghi <?>>>> listFour`.感谢简明扼要的解释和有用的链接; 它现在更加清晰. (4认同)