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
这是为了避免你绕过generics类型的情况:
final List strings = ... final List
所以,逐个浏览你的例子
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
- 它可以是List
或List
; 我们可以从它作为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
。