generics,类型参数和通配符

我试图理解javagenerics,它们似乎很难理解。 例如,这很好……

public class Main { public static void main(String[] args) { List list = null; method(list); } public static  void method(List list) { } } 

……就这样……

 public class Main { public static void main(String[] args) { List<List> list = null; method(list); } public static  void method(List list) { } } 

… 和这个 …

 public class Main { public static void main(String[] args) { List<List<List>> list = null; method(list); } public static  void method(List<List> list) { } } 

…但这不编译:

 public class Main { public static void main(String[] args) { List<List> list = null; method(list); } public static  void method(List<List> list) { } } 

有人可以用简单的语言解释发生了什么吗?

通用类型要理解的主要问题是它们不是协变的。

所以你可以这样做:

 final String string = "string"; final Object object = string; 

以下内容无法编译:

 final List strings = ... final List objects = strings; 

这是为了避免你绕过generics类型的情况:

 final List strings = ... final List objects = strings; objects.add(1); final String string = strings.get(0); <-- oops 

所以,逐个浏览你的例子

1

你的generics方法采用List ,你传入一个List ; 它(基本上)是List 。 可以将T分配给Object类型,编译器也很满意。

2

您的通用方法是相同的,您传入List>T可以分配给List类型,编译器也很高兴。

3

这与另一个嵌套级别的2基本相同。 T仍然是List类型。

4

这里是一个小梨形的地方,我从上面的点进来。

您的generics方法采用List> 。 您传入List> 。 现在,由于generics类型不协变,因此无法将List分配给List

实际的编译器错误(Java 8)是:

required: java.util.List> found: java.util.List> reason:无法推断type-variable(s) T (参数不匹配; java.util.List>无法转换为java.util.List>

基本上编译器告诉你它找不到要分配的T ,因为必须推断嵌套在外部列表中的List的类型。

让我们更详细地看一下这个:

List是一个未知类型List - 它可以是ListList ; 我们可以从它作为Object get但我们无法add 。 因为否则我们遇到了我提到的协方差问题。

List>是一些未知类型的List - 它可以是List>List> 。 在案例1中 ,可以将T分配给Object ,而不允许在通配符列表上add操作。 在案例4中,这不能完成 - 主要是因为没有一个generics构造来阻止add到外部List

如果编译器在第二种情况下将T分配给Object ,则可能出现以下内容:

 final List> list = ... final List> wildcard = list; wildcard.add(Arrays.asList("oops")); 

因此,由于协方差,无法安全地将List>分配给任何其他通用List