[英]getClass() of a Generic Method Parameter in a Java
以下Java方法无法编译:
<T extends Number> void foo(T t)
{
Class<? extends T> klass = t.getClass();
}
收到的错误是:类型不匹配:无法转换为Class<capture#3-of ? extends Number>
Class<capture#3-of ? extends Number>
为Class<? extends T>
Class<? extends T>
有人可以解释为什么Class<? extends T>
Class<? extends T>
无效,但Class<? extends Number>
Class<? extends Number>
?
Javadoc说:
实际的结果类型是
Class<? extends |X|>
Class<? extends |X|>
where | X | 是调用getClass的表达式的静态类型的擦除。 例如,此代码片段中不需要强制转换:
Number n = 0;
Class<? extends Number> c = n.getClass();
因为T
类'类型不会从T
延伸。 相反,它从Number
扩展,正如您在<T extends Number>
。 就那么简单。
一个更好的问题是:
以下为什么不编译?
<T extends Number> void foo(T t) { Class<T> class1 = t.getClass(); }
答案是Object#getClass()
返回带有无界通配符的Class<?>
?
因为对象本身并不直接了解其在任意方法中所期望的泛型类型。
这有点傻。 对于大多数用例,如果x.getClass()
返回Class<? extends X>
Class<? extends X>
,而不是擦除的Class<? extends |X|>
Class<? extends |X|>
。
擦除是导致信息丢失的原因,使您的代码显然是安全的,无法编译。 t.getClass()
返回Class<? extends |T|>
Class<? extends |T|>
和|T| = Number
|T| = Number
,所以返回Class<? extends Number>
Class<? extends Number>
。
擦除(由语言规范强制要求)是为了保持理论上的正确性。 例如
List<String> x = ...;
Class<List> c1 = x.getClass(); // ok
Class<List<String>> c2 = x.getClass(); // error
虽然c2看起来很合理,但在Java中, List<String>
实际上没有这样的类。 List
只有一个类。 所以允许c2在理论上是不正确的。
这种形式在现实世界的用法中产生了很多问题,程序员可以推断出Class<? extends X>
Class<? extends X>
对于他们的目的是安全的,但必须处理已删除的版本。
您可以简单地定义自己的getClass
,返回未擦除的类型
static public <X> Class<? extends X> getFullClass(X x)
return (Class<? extends X>)(Class) x.getClass() ;
<T extends Number> void foo(T t)
{
Class<? extends T> klass = getFullClass(t);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.