// #1 (does compile)
List raw = null;
List<?> wild = raw;
// #2 (doesn't compile)
List<List> raw = null;
List<List<?>> wild = raw;
首先让我们理清为什么这些实际上是不相关的作业。也就是说,它们受不同的规则管辖。
#1 被称为unchecked conversion:
存在从原始类或接口类型 (§4.8) G 到 G<T<sub>1</sub>,...,T<sub>n</sub>> 形式的任何参数化类型的未经检查的转换。
具体来说,它是 assignment context 的特例,仅适用于这种情况:
如果在应用 [其他可能的转换] 之后,结果类型是原始类型,则可能会应用未经检查的转换。
#2 需要引用类型转换;但是它的问题在于它不是widening conversion(这是一种在没有强制转换的情况下隐式允许的引用转换)。
这是为什么呢?嗯,这是由rules of generic subtyping 尤其是这个要点特别管理的:
给定一个泛型类型声明C<F<sub>1</sub>,...,F<sub>n</sub>> (n > 0),参数化类型C<T<sub>1</sub>,...,T<sub>n</sub>>的直接超类型,其中T<sub>i</sub> (1 ≤ i ≤ n) 是一个类型,都是以下几种:
-
C<S<sub>1</sub>,...,S<sub>n</sub>>,其中S<sub>i</sub> 包含T<sub>i</sub> (1 ≤ i ≤ n)。
这指的是 JLS 称为 containment 的东西,要成为有效赋值,左侧的参数必须包含右侧的参数。包含主要控制通用子类型,因为"concrete" generic types 是invariant。
您可能熟悉以下想法:
-
List<Dog> 不是List<Animal>
- 但
List<Dog> 是List<? extends Animal>。
嗯,后者是真的,因为? extends Animal 包含 Dog。
所以问题变成了“类型参数List<?> 是否包含原始类型参数List”?答案是否定的:虽然List<?> 是List 的子类型,但这种关系不适用于类型参数。
没有特殊的规则可以证明这一点:List<List<?>> 不是List<List> 的子类型,原因基本相同,List<Dog> 不是List<Animal> 的子类型。
所以因为List<List> 不是List<List<?>> 的子类型,所以赋值无效。同样,您不能执行直接的narrowing conversion 转换,因为List<List> 也不是List<List<?>> 的超类型。
要进行分配,您仍然可以应用演员表。在我看来,有三种方法可以做到这一点。
// 1. raw type
@SuppressWarnings("unchecked")
List<List<?>> list0 = (List) api();
// 2. slightly safer
@SuppressWarnings({"unchecked", "rawtypes"})
List<List<?>> list1 = (List<List<?>>) (List<? extends List>) api();
// 3. avoids a raw type warning
@SuppressWarnings("unchecked")
List<List<?>> list2 = (List<List<?>>) (List<? super List<?>>) api();
(你可以用JAXBElement代替内部的List。)
此转换的用例应该是安全的,因为 List<List<?>> 是比 List<List> 更严格的类型。
原始类型 语句是一个扩大的转换然后是未经检查的分配。这是因为,如上所示,任何参数化类型都可以转换为其原始类型,反之亦然。
-
稍微安全语句(之所以这样命名是因为它丢失的类型信息较少)是一个加宽转换然后是窄化转换。这通过强制转换为一个共同的超类型来工作:
List<? extends List>
╱ ╲
List<List<?>> List<List>
有界通配符允许考虑通过包含进行子类型化的类型参数。
List<? extends List> 被认为是List<List<?>> 的超类型这一事实可以通过传递性来证明:
? extends List 包含? extends List<?>,因为List 是List<?> 的超类型。
? extends List<?> 包含List<?>。
-
因此? extends List 包含List<?>。
(即List<? extends List> :> List<? extends List<?>> :> List<List<?>>。)
第三个示例的工作方式与第二个示例类似,通过转换为通用超类型List<? super List<?>>。由于它不使用原始类型,我们可以减少一个警告。
这里的非技术总结是规范暗示List<List>和List<List<?>>之间既没有子类型也没有超类型关系。
虽然从List<List> 转换为List<List<?>> 应该是安全,但这是不允许的。 (这是安全的,因为两者都是 List,可以存储任何类型的 List,但 List<List<?>> 对其元素在检索后的使用方式施加了更多限制。)
不幸的是,除了原始类型很奇怪并且它们的使用存在问题之外,没有任何实际原因无法编译。