Mik*_*keM 9 java generics reflection
以下Java方法无法编译:
<T extends Number> void foo(T t)
{
Class<? extends T> klass = t.getClass();
}
Run Code Online (Sandbox Code Playgroud)
收到的错误是:类型不匹配:无法转换Class<capture#3-of ? extends Number>为Class<? extends T>
有人可以解释为什么Class<? extends T>无效,但是没问题Class<? extends Number>吗?
Javadoc说:
实际结果类型是
Class<? extends |X|>| X | 是调用getClass的表达式的静态类型的擦除.例如,此代码片段中不需要强制转换:
Number n = 0;
Class<? extends Number> c = n.getClass();
Run Code Online (Sandbox Code Playgroud)
因为T类的类型不会延伸T.相反,它Number完全按照你宣称自己的方式延伸<T extends Number>.就那么简单.
一个更好的问题是:
以下为什么不编译?
Run Code Online (Sandbox Code Playgroud)<T extends Number> void foo(T t) { Class<T> class1 = t.getClass(); }
答案是带有无界通配符的Object#getClass()返回Class<?>,?因为对象本身并不直接了解其在任意方法中所期望的泛型类型.
这有点傻。x.getClass()对于大多数用例来说,如果返回 Class<? extends X>,而不是 擦除 ,那就更好了Class<? extends |X|>。
擦除会导致信息丢失,从而使看似安全的代码无法编译。t.getClass()返回Class<? extends |T|>、 和|T| = Number,因此返回Class<? extends Number>。
擦除(由语言规范强制执行)是为了保持理论上的正确性。例如
List<String> x = ...;
Class<List> c1 = x.getClass(); // ok
Class<List<String>> c2 = x.getClass(); // error
Run Code Online (Sandbox Code Playgroud)
虽然c2看起来很合理,但是在Java中,确实没有这样的类List<String>。只有 的课程List。因此,理论上允许 c2 是不正确的。
这种形式在现实世界的使用中产生了很多问题,程序员可以推断这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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1932 次 |
| 最近记录: |