// #1 (does compile)
List raw = null;
List<?> wild = raw;
// #2 (doesn't compile)
List<List> raw = null;
List<List<?>> wild = raw;
首先,让我们搞清楚为什么它们实际上是不相关的任务。也就是说,它们受到不同的规则支配。
#1 被称为 未经检查的转换:
从原始类或接口类型(§4.8) G
到任何形式为 G<T1,...,Tn>
的参数化类型存在一个未经检查的转换。
具体来说,它是一种特殊情况的 赋值上下文,仅适用于此场景:
如果在应用 [其他可能的转换] 后,结果类型是原始类型,则可以应用未经检查的转换。
#2需要进行引用类型转换,但问题在于它不是扩展转换(这是一种可以隐式允许无需强制转换的引用转换)。
为什么呢?好吧,这是由通用子类型规则特别控制的,更具体地说,是由以下要点控制:
给定一个通用类型声明
C<F1,...,Fn>
(
n > 0),参数化类型
C<T1,...,Tn>
的
直接超类型,其中
Ti
(1 ≤
i ≤
n)是一种类型,包括以下所有内容:
C<S1,...,Sn>
,其中 Si
包含 Ti
(1 ≤ i ≤ n)。
这里涉及到JLS所称的
包容性,即为了成为有效赋值,左侧参数必须
包含右侧参数。包容性在很大程度上管理着通用子类型,因为
"具体"泛型类型是
不变的。
你可能熟悉以下思想:
-
List<Dog>
不是
List<Animal>
- 但是
List<Dog>
是
List<? extends Animal>
嗯,后者是正确的,因为
? extends Animal
包含Dog
。
所以问题变成了“类型参数
List<?>
是否包含原始类型参数
List
”?答案是不:尽管
List<?>
是
List
的子类型,但这种关系不适用于类型参数。
没有特殊规则使其成立:
List<List<?>>
基本上由于与
List<Dog>
不是
List<Animal>
的原因而不是
List<List>
的子类型。
因此,由于
List<List>
不是
List<List<?>>
的子类型,该赋值无效。同样地,您也不能执行直接的
缩小转换强制转换,因为
List<List>
也不是
List<List<?>>
的超类型。
为了完成这个任务,你仍然可以应用强制类型转换。我认为有三种合理的方法来实现它。
@SuppressWarnings("unchecked")
List<List<?>> list0 = (List) api();
@SuppressWarnings({"unchecked", "rawtypes"})
List<List<?>> list1 = (List<List<?>>) (List<? extends List>) api();
@SuppressWarnings("unchecked")
List<List<?>> list2 = (List<List<?>>) (List<? super List<?>>) api();
你可以将内部的
List
替换为
JAXBElement
。使用这种类型转换应该是安全的,因为
List<List<?>>
比
List<List>
更加限制严格。
The raw type statement is a widening cast then unchecked assignment. This works because, as shown above, any parameterized type can be converted to its raw type and vice-versa.
The slightly safer statement (named as such because it loses less type information) is a widening cast then narrowing cast. This works by casting to a common supertype:
List<? extends List>
╱ ╲
List<List<?>> List<List>
The bounded wildcard allows the type arguments to be considered for subtyping via containment.
The fact that List<? extends List>
is considered a supertype of List<List<?>>
can be proven with transitivity:
? extends List
contains ? extends List<?>
, because List
is a supertype of List<?>
.
? extends List<?>
contains List<?>
.
Therefore ? extends List
contains List<?>
.
(That is, List<? extends List> :> List<? extends List<?>> :> List<List<?>>
.)
The third example works in a way that's similar to the second example, by casting to a common supertype List<? super List<?>>
. Since it doesn't use a raw type, we can suppress one less warning.
这里的非技术总结是,规范意味着
List<List>
和
List<List<?>>
之间既没有子类型关系也没有超类型关系。
尽管从
List<List>
转换为
List<List<?>>
应该是安全的,但是不允许这样做。(因为两者都是可以存储任何类型的
List
,但
List<List<?>>
对其检索后如何使用其元素有更多限制。)
不幸的是,这种编译错误没有实际原因,只是因为原始类型很奇怪,使用它们会出现问题。
List<JAXBElement<String>>
,请将其转换为该类型,而不是List<?>
或List<JAXBElement<?>>
。如果您知道所有类型,请避免使用问号。 - Mike 'Pomax' Kamermans无法将List<List>强制转换为List<List<String>>
(当然不能通过中间转换为Object之类的方式)。 - djeikybIterable
,将操作由api()返回的单个JAXBElement<String>
实例,因此是允许的。 - Mark