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

时间:2011-09-01 20:27:28

标签: java generics reflection

以下Java方法无法编译:

<T extends Number> void foo(T t)
{
    Class<? extends T> klass = t.getClass();
}

收到的错误是: 类型不匹配:无法从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(); 

2 个答案:

答案 0 :(得分:5)

因为T类'类型未从T延伸。相反,它从Number延伸,正如您在<T extends Number>中声明的那样。就那么简单。

更好的问题是:

  

为什么不进行以下编译?

<T extends Number> void foo(T t)
{
    Class<T> class1 = t.getClass();
}

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

答案 1 :(得分:3)

有点傻。对于大多数用例,如果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

尽管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);
}