// #1 (does compile)
List raw = null;
List> wild = raw;
// #2 (doesn't compile)
List raw = null;
List> wild = raw;
首先让我们弄清楚为什么这些实际上是无关的任务。也就是说,它们受不同的规则支配。
有一个
从原始类或接口类型(
§4.8
G
到窗体的任何参数化类型
G
1
,...,T
n
>
.
如果在应用[其他可能的转换]之后,结果类型是原始类型,则可以应用未经检查的转换。
#2需要引用类型转换;但是它的问题是它不是
widening conversion
给定泛型类型声明
C
1
,...,F
n
>
n个
>0),则
参数化类型的
C
1
,...,T
n
>
,其中
T
i
我
n个
)是一种类型,是否都是以下类型:
C
1
,...,S
n
>
,其中
S
i
T型
我
(1¥
¤
n个
这是指JLS所说的
containment
,如果要成为有效的赋值,则左侧的参数必须
包含
右边的论点。包容在很大程度上控制了通用子类型,因为
"concrete" generic types
是
invariant
.
您可能熟悉以下想法:
一
List
List
但是
是一个
List extends Animal>
.
好吧,后者是真的,因为
? extends Animal
Dog
.
所以问题变成
“”执行类型参数
List>
包含原始类型参数
List
? 答案是否定的:尽管
列表>
列表
,此关系不适用于类型参数。
没有什么特别的规则可以证明这一点:
List>
不是的子类型
List
列表
不是的子类型
.
所以因为
列表
不是的子类型
,分配无效。同样,您不能执行
narrowing conversion
投球是因为
不是
列表gt;
或者。
// 1. raw type
@SuppressWarnings("unchecked")
List> list0 = (List) api();
// 2. slightly safer
@SuppressWarnings({"unchecked", "rawtypes"})
List> list1 = (List>) (List extends List>) api();
// 3. avoids a raw type warning
@SuppressWarnings("unchecked")
List> list2 = (List>) (List super List>>) api();
(您可以替换
JAXBElement
列表
这个铸件的用例应该是安全的,因为
列表gt;
是一种比
列表
这个
语句是加宽强制转换,然后是未选中的赋值。这是因为,如上所示,任何参数化类型都可以转换为其原始类型,反之亦然。
这个
稍微安全一点
语句(这样命名是因为它丢失的类型信息更少)是加宽型转换,然后是窄型转换。它通过投射到一个常见的超类型来工作:
List extends List>
â± â²
List> List
有界通配符允许在通过包含进行子类型化时考虑类型参数。
事实上
List extends List>
被认为是
可通过传递性证明:
? extends List
包含
? extends List>
列表
是
列表>
?扩展列表>
包含
列表>
因此
?扩展列表
列表>
(也就是说,
List extends List> :> List extends List>> :> List>
.)
第三个示例的工作方式与第二个示例类似,它将强制转换为一个通用的超类型
List super List>>
这里的非技术性总结是,规范意味着在
列表
和
列表gt;
尽管从
列表
到
应该是
安全的
列表
可以储存任何种类的
列表
,但是
对检索后如何使用其元素施加了更多限制。)
不幸的是,除了原始类型很奇怪并且使用它们有问题之外,没有任何实际的原因无法编译。