9

假设我在 Java 中有这个:

List<String> list = new ArrayList<String>();
list.getClass();

最后一个表达式的类型是Class<? extends List>。我明白为什么由于擦除,它不能是Class<? extends List<String>>. 但为什么不能呢Class<? extends List<?>>

如果我想将此表达式的结果分配给以某种方式保留此类实际上是某种信息的变量,我是否无法避免未经检查的强制转换警告原始类型警告List

Class<? extends List> listClass = list.getClass(); // raw type warning
Class<? extends List<?>> listClass = (Class<? extends List<?>>) list.getClass(); // unchecked cast warning
4

2 回答 2

7

首次引入泛型时,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

理由:

  1. 该规则引入了原始类型。原始类型只能用于与遗留代码交互。

  2. 新规则引入了通配符。参数化类型和通配符之间的关系基于子类型规则。参数化类型和通配符之间的关系基于原始类型转换。

这个错误没有被采取行动,直到今天仍然开放,有以下反驳:

该提议意味着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()已经做到的。

总体而言,该提案似乎是一个好主意,但它具有中等复杂性和相当小的回报。

(有删节,部分错别字更正)

于 2013-09-15T21:37:12.200 回答
-3

由于那List是一个接口,我不确定是否有可能发现该List接口是为ArrayList. 在此处找到此链接可能会有所帮助。

我确实搞砸了一段时间,发现......

    Class<?> d = list.getClass();
    d.equals(ArrayList.class);

但我不确定这是否是你要找的……

祝你好运!

于 2013-09-14T02:41:22.567 回答