Java中的通用方法参数的getClass()

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)

Bal*_*usC 5

因为T类的类型不会延伸T.相反,它Number完全按照你宣称自己的方式延伸<T extends Number>.就那么简单.

一个更好的问题是:

以下为什么不编译?

<T extends Number> void foo(T t)
{
    Class<T> class1 = t.getClass();
}
Run Code Online (Sandbox Code Playgroud)

答案是带有无界通配符的Object#getClass()返回Class<?>,?因为对象本身并不直接了解其在任意方法中所期望的泛型类型.


irr*_*ble 5

这有点傻。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)