我正在阅读Maurice Naftalin的书Java generics and collections
。
在关于通配符捕获的部分中,作者举了一个例子
public static void reverse(List<?> list) {
rev(list);
}
private static <T> void rev(List<T> list) {
List<T> tmp = new ArrayList<T>(list);
for (int i = 0; i < list.size(); i++) {
list.set(i, tmp.get(list.size()-i-1));
}
}
但我认为类型List<T>
是List<?>
的子类型(其中List<?>
是List<? extends Object>
的简写语法)(我对List<T>
的假设是List<? extends Object>
的子类型甚至是正确的吗?),因此在reverse
方法中,我们如何将变量list
(List<? extends Object>
}类型传递给rev
方法, rev
方法参数的类型为List<T>
?
答案 0 :(得分:3)
我们如何将变量列表(类型
List<? extends Object>
)传递给rev方法
你不是。
每个列表都有一个类型:您无法创建new ArrayList<?>
或new ArrayList<? extends String>
。您可以创建new ArrayList<String>
,并将其分配给具有通配符类型的变量。
所以,你可以调用一个方法List<T>
,即使有List<?>
作为参数,只要编译器可以推断出某些类型与界限。你不知道类型,但编译器可以。
答案 1 :(得分:2)
但我认为类型
的子类型List<T>
是List<?>
事实并非如此:请记住,Java中的泛型是不变的。这意味着即使X是Y的子类型,List<X>
也不会是List<Y>
的子类型。
代码示例的工作原因是reverse
方法匹配任何List
类型,甚至是原始类型。
答案 2 :(得分:2)
在此声明中:
private static <T> void rev(List<T> list) {...}
T
是一种方法参数化类型,没有显式绑定引用任何类型。
您可以在方法中传递一个声明为List<? extends Object>
,List<?>
甚至List<String>
的变量,因为它接受List
中的任何类型。