[英]Generics, Type Parameters and Wildcards
我试图理解java泛型,它们似乎非常难以理解。 例如,这很好......
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) { }
}
有人可以用简单的语言解释发生了什么吗?
通用类型要理解的主要问题是它们不是协变的。
所以你可以这样做:
final String string = "string";
final Object object = string;
以下内容无法编译:
final List<String> strings = ...
final List<Object> objects = strings;
这是为了避免您绕过泛型类型的情况:
final List<String> strings = ...
final List<Object> objects = strings;
objects.add(1);
final String string = strings.get(0); <-- oops
所以,逐个浏览你的例子
你的泛型方法采用List<T>
,你传入一个List<?>
; 它(基本上)是一个List<Object>
。 可以将T
分配给Object
类型,编译器也很满意。
您的通用方法是相同的,您传入List<List<?>>
。 T
可以分配给List<?>
类型,编译器也很高兴。
这与另一个嵌套级别的2基本相同。 T
仍然是List<?>
类型。
这里是一个小梨形的地方,我从上面的点进来。
您的泛型方法采用List<List<T>>
。 您传入List<List<?>>
。 现在,由于泛型类型不协变,因此无法将List<?>
分配给List<T>
。
实际的编译器错误(Java 8)是:
required:
java.util.List<java.util.List<T>>
found:java.util.List<java.util.List<?>>
reason:无法推断类型变量T
(参数不匹配;java.util.List<java.util.List<?>>
无法转换为java.util.List<java.util.List<T>>
)
基本上编译器告诉你它找不到要分配的T
,因为必须推断嵌套在外部列表中的List<T>
的类型。
让我们更详细地看一下这个:
List<?>
是一个未知类型的List
- 它可以是List<Integer>
或List<String>
; 我们可以从它get
Object
, 但我们无法add
。 因为否则我们遇到了我提到的协方差问题。
List<List<?>>
是一个List
的List
一些未知类型的-它可能是一个List<List<Integer>>
或List<List<String>>
。 在案例1中 ,可以将T
分配给Object
,而不允许在通配符列表上add
操作。 在案例4中,这不可能完成 - 主要是因为没有一个泛型构造来阻止add
到外部List
。
如果编译器在第二种情况下将T
分配给Object
,则可能出现以下内容:
final List<List<Integer>> list = ...
final List<List<?>> wildcard = list;
wildcard.add(Arrays.asList("oops"));
因此,由于协方差,无法安全地将List<List<Integer>>
分配给任何其他通用List
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.