在Java中,在generics类型的实例上调用getClass时如何避免原始类型?
假设我在Java中有这个:
List list = new ArrayList(); list.getClass();
最后一个表达式的类型是Class
Class
。 我理解为什么,由于擦除,它不能是Class<? extends List>
Class<? extends List>
。 但为什么不能成为Class<? extends List>
Class<? extends List>
?
如果我想将这个表达式的结果分配给一个变量,以某种方式保存这个类实际上是某种List
的信息,我是否有办法避免未经检查的强制转换警告和原始类型警告 ?
Class listClass = list.getClass(); // raw type warning Class<? extends List> listClass = (Class<? extends List>) list.getClass(); // unchecked cast warning
首次引入generics时, getClass
返回Class extends X>
Class extends X>
,其中X
是调用它的表达式的静态类型。 这种行为导致了不合理的编译问题,正如此Oracle错误中所报告的那样。 这是bug报告的例子:
以下程序片段无法编译
void f(List
li, List ls) { if (li.getClass() == ls.getClass()) ; } 因为
Class
和>
Class
的交集是空的。>
通过将getClass
的返回类型扩展为现在的问题来解决此问题。 从文档 :
实际的结果类型是
Class extends |X|>
Class extends |X|>
where|X|
是擦除调用getClass
的表达式的静态类型。
这解决了上述问题,但因此导致了您的问题指出的问题。 不久之后,报告了另一个错误 ,争论如下:
我认为
getClass()
类型规则可以更改为Class extends wildcard(T)>
Class extends wildcard(T)>
通配符操作定义如下:如果
T
是参数化的,则wildcard(T)=erasure(T)>
否则,wildcard(T)=T
理由:
此规则引入原始类型。 原始类型必须仅用于与遗留代码交互。
新规则引入了通配符。 参数化类型和通配符之间的关系基于子类型规则。 参数化类型和通配符之间的关系基于原始类型转换。
这个错误没有采取行动,至今仍未解决,并提出以下抗议:
该提议意味着
getClass()
将返回一个Class extends ArrayList>>
Class extends ArrayList>>
对象,它与其他Class extends ArrayList>>
不兼容Class extends ArrayList>>
对象。 这与现有代码兼容:List
l = ...; Class extends List> c = l.getClass(); 因为新型的RHS,
Class extends List>>
Class extends List>>
,是Class extends List>
的子类型Class extends List>
Class extends List>
。丰富Class类型参数的一个缺点是它会破坏
Class.cast
习惯用法。 今天你可以写:List
x = ...; Class extends List> cl = x.getClass(); List y = cl.cast(null); 并且在
cast()
处获得警告,因为从List
到List
的未经检查的转换。 但是根据提案,类似的代码不能编译:List
x = ...; Class extends List>> cl = x.getClass(); List y = cl.cast(null); 因为
cast()
返回的List>
无法转换为List
。 避免错误的唯一方法是将cl.cast(..)
强制转换为List
,并将未经检查的转换警告置于List
。 这实际上就是getClass()
已经做到的。总体而言,该提案似乎是一个好主意,但它具有中等复杂性和相当小的收益。
(删节并纠正了一些拼写错误)
由于List
是一个接口,我不确定是否有可能发现List
接口是为ArrayList
实现的。 在这里找到这个可能有帮助的链接。
我确实搞砸了一下,发现……
Class> d = list.getClass(); d.equals(ArrayList.class);
但我不确定这是不是你要找的……
祝好运!