首次引入泛型时,getClass
返回了调用它的表达式的静态类型在Class<? extends X>
哪里。X
此行为导致不合理的编译问题,如本 Oracle 错误中所述。这是该错误报告的示例:
以下程序片段无法编译
void f(List<Integer> li, List<String> ls) {
if (li.getClass() == ls.getClass())
;
}
因为 和 的交集Class<List<Integer>>
是
Class<List<String>>
空的。
此问题已通过将返回类型扩大getClass
到现在的方式得到解决。从文档中:
实际结果类型是Class<? extends |X|>
在哪里擦除调用|X|
的表达式的静态类型。getClass
这解决了上述问题,但因此导致了您的问题指出的问题。不久之后,报告了另一个错误,争论如下:
我认为getClass()
打字规则可以更改为Class<? extends
wildcard(T)>
通配符操作定义为: ifT
参数化,
wildcard(T)=erasure(T)<?>
else ,
wildcard(T)=T
理由:
该规则引入了原始类型。原始类型只能用于与遗留代码交互。
新规则引入了通配符。参数化类型和通配符之间的关系基于子类型规则。参数化类型和通配符之间的关系基于原始类型转换。
这个错误没有被采取行动,直到今天仍然开放,有以下反驳:
该提议意味着getClass()
将返回一个Class<? extends
ArrayList<?>>
与其他对象不兼容的Class<? extends
ArrayList<?>>
对象。这与现有代码兼容,例如:
List<String> l = ...;
Class<? extends List> c = l.getClass();
因为 RHS 的新类型Class<? extends List<?>>
, 是 的子类型
Class<? extends List>
。
丰富 Class 的类型参数的一个缺点是它会破坏Class.cast
. 今天,你可以写:
List<Integer> x = ...;
Class<? extends List> cl = x.getClass();
List<Integer> y = cl.cast(null);
并在 处收到警告cast()
,因为从List
到的未经检查的转换List<Integer>
。但是对于该提案,类似的代码无法编译:
List<Integer> x = ...;
Class<? extends List<?>> cl = x.getClass();
List<Integer> y = cl.cast(null);
因为List<?>
返回的cast()
无法转换为List<Integer>
. 避免错误的唯一方法是
强制cl.cast(..)
转换List
并遭受未经检查的转换警告到
List<Integer>
. 这实际上是getClass()
已经做到的。
总体而言,该提案似乎是一个好主意,但它具有中等复杂性和相当小的回报。
(有删节,部分错别字更正)