通用类型要了解的主要内容是它们不是协变的。
所以你可以这样做:
final String string = "string";
final Object object = string;
以下将不会编译:
final List strings = ...
final List objects = strings;
这是为了避免您规避泛型类型的情况:
final List strings = ...
final List objects = strings;
objects.add(1);
final String string = strings.get(0);
所以,一个个通过你的例子
1
您的通用方法采用列表< T>,您传递列表;这是(基本上)List< Object>。 T可以分配给对象类型,编译器很高兴。
2
您的通用方法相同,您传递列表>。 T可以分配给列表类型和编译器再次开心。
3
这与基本相同,具有另一个嵌套级别。 T仍然是列表类型。
4
这里是一个小梨形状,从上方来的地方在哪里。
您的通用方法采用List< List< T>。您传递列表>。现在,由于通用类型不是协变的,List不能分配给List< T>。
实际的编译器错误(Java 8)是:
required: java.util.List> found:
java.util.List> reason: cannot infer
type-variable(s) T
(argument mismatch; java.util.List> cannot be converted to java.util.List>)
基本上,编译器告诉你,由于必须推断出List< T>的类型,它找不到要分配的T。嵌套在外部列表中。
让我们再来一些细节:
列表与LT;?>是一些未知类型的列表 – 它可以是List< Integer>或List< String>;我们可以从Object获取,但是我们不能添加。因为否则我们遇到了我提到的协方差问题。
列表与LT;列表与LT;?>>是某个未知类型的列表的列表 – 它可以是List< List< Integer>>或列表>。在情况1中,可以将T分配给对象,并且不允许在通配符列表上添加操作。在这种情况下,这不能完成 – 主要是因为没有泛型构造来阻止添加到外部列表。
如果编译器在第二种情况下将T分配给Object,则可以执行以下操作:
final List> list = ...
final List> wildcard = list;
wildcard.add(Arrays.asList("oops"));
因此,由于协方差,不可能分配List< List< Integer>>到任何其他通用列表安全。