泛型、类型参数和通配符 [英] Generics, Type Parameters and Wildcards
问题描述
我正在尝试理解 Java 泛型,但它们似乎非常难以理解.例如,这很好...
I am trying to understand java generics and they seem extremely difficult to understand. For example, this is fine...
public class Main {
public static void main(String[] args) {
List<?> list = null;
method(list);
}
public static <T> void method(List<T> list) { }
}
...原来如此...
public class Main {
public static void main(String[] args) {
List<List<?>> list = null;
method(list);
}
public static <T> void method(List<T> list) { }
}
...还有这个...
public class Main {
public static void main(String[] args) {
List<List<List<?>>> list = null;
method(list);
}
public static <T> void method(List<List<T>> list) { }
}
...但这不能编译:
public class Main {
public static void main(String[] args) {
List<List<?>> list = null;
method(list);
}
public static <T> void method(List<List<T>> list) { }
}
有人可以用简单的语言解释发生了什么吗?
Can someone explain what is going on in simple language?
推荐答案
要理解泛型类型的主要内容是它们不是协变的.
The main thing to understand with generic types, is that they aren't covariant.
所以虽然你可以这样做:
So whilst you can do this:
final String string = "string";
final Object object = string;
以下不会编译:
final List<String> strings = ...
final List<Object> objects = strings;
这是为了避免绕过泛型类型的情况:
This is to avoid the situations where you circumvent the generic types:
final List<String> strings = ...
final List<Object> objects = strings;
objects.add(1);
final String string = strings.get(0); <-- oops
所以,一个一个地浏览你的例子
So, going through your examples one by one
你的泛型方法需要一个List
,你传入一个List>
;它(本质上)是一个 List
.T
可以赋值给 Object
类型,编译器很开心.
Your generic method takes a List<T>
, you pass in a List<?>
; which is (essentially) a List<Object>
. T
can be assigned to the Object
type and the compiler is happy.
你的通用方法是一样的,你传入一个List
.T
可以分配给 List>
类型,编译器又开心了.
Your generic method is the same, you pass in a List<List<?>>
. T
can be assigned to the List<?>
type and the compiler is again happy.
这与 2 基本相同,只是多了一层嵌套.T
仍然是 List>
类型.
This is basically the same as 2 with another level of nesting. T
is still the List<?>
type.
这是一个梨形的地方,也是我从上面的观点进来的地方.
Here is where it goes a little pear shaped, and where my point from above comes in.
您的通用方法采用 List
.你传入一个 >
List
.现在,由于泛型类型不是协变的,>
List>
不能分配给 List
.
Your generic method takes a List<List<T>>
. You pass in a List<List<?>>
. Now, as generic types are not covariant, List<?>
cannot be assigned to a List<T>
.
实际的编译器错误(Java 8)是:
The actual compiler error (Java 8) is:
必需:java.util.List
找到:java.util.List
原因:无法推断类型变量T
(参数不匹配;java.util.List
无法转换为 java.util.List
)
required:
java.util.List<java.util.List<T>>
found:java.util.List<java.util.List<?>>
reason: cannot infer type-variable(s)T
(argument mismatch;java.util.List<java.util.List<?>>
cannot be converted tojava.util.List<java.util.List<T>>
)
基本上,编译器告诉您它找不到要分配的 T
,因为必须推断嵌套在外部列表中的 List
的类型.
Basically the compiler is telling you that it cannot find a T
to assign because of having to infer the type of the List<T>
nested in the outer list.
让我们更详细地看看这个:
Lets look at this in a little more detail:
List>
是某种未知类型的List
- 它可能是一个 List
或 List
;我们可以从它get
作为Object
,但我们不能add
.因为否则我们就会遇到我提到的协方差问题.
List<?>
is a List
of some unknown type - it could be a List<Integer>
or a List<String>
; we can get
from it as Object
, but we cannot add
. Because otherwise we run into the covariance issue I mentioned.
List<List>>
是某种未知类型的 List
的 List
- 它可能是一个 List
或 >
List
.在 1 的情况下,可以将 >
T
分配给 Object
并且不允许对通配符列表进行 add
操作.如果 4 不能这样做 - 主要是因为没有泛型结构来防止 add
到外部 List
.
List<List<?>>
is a List
of List
of some unknown type - it could be a List<List<Integer>>
or a List<List<String>>
. In case 1 it was possible to assign T
to Object
and just not allow add
operations on wildcard list. In case 4 this cannot be done - primarily because there is not a generics construct to prevent add
to the outer List
.
如果编译器要在第二种情况下将 T
分配给 Object
,则可能会出现以下情况:
If the compiler were to assign T
to Object
in the second case then something like the following would be possible:
final List<List<Integer>> list = ...
final List<List<?>> wildcard = list;
wildcard.add(Arrays.asList("oops"));
因此,由于协方差,不可能将 List
分配给 任何其他泛型 >
List
安全.
So, due to covariance, it is not possible to assign a List<List<Integer>>
to any other generic List
safely.
这篇关于泛型、类型参数和通配符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!