没关系:
Class<? extends String> stringClass = "a".getClass();
但这会出错:
<T> void f(T obj) {
Class<? extends T> objClass = obj.getClass();
}
我知道我可以像:
<T> void f(T obj) {
@SuppressWarnings("unchecked")
Class<? extends T> objClass = (Class<? extends T>) obj.getClass();
}
但为什么以前的错误呢?下一版Java 7是否会支持这种用法?
修改
我处理类型擦除没有问题,只要我的代码正确就加上SuppressWarnings
,但编译器不支持它。
背后的问题是,SuppressWarnings
还不够。当T.getClass() => ? extends T
明显直观时,我为什么要压制任何警告?
正如您在javadoc中看到的那样:
实际结果类型是Class,其中| X |是擦除调用getClass的表达式的静态类型。
当我们谈论Java泛型时,Object.getClass()
是一个特例。它与声明的形式不同,它只返回Classs<?>
。我不知道如何实现IDE之类的IDE,在Eclipse IDE中,完成将为您生成Class<? extends |X|>
而不是Class<?>
。我想在Object类中可能有一些神奇的东西,要制作基类型,哪个?从派生类型扩展,不同。因此,用Java语言编写自己的Object类是不可能的,这将返回? extends |X|
|X|
this.getClass()
Object
之类的内容。但Java {{1}}确实如此,因为它是一个特例。
答案 0 :(得分:2)
Class
表示JVM中的类,而不是Java语言。因此,对于List<String>
,实际Class
为Class<List>
。在您的示例中,如果T
为List<String>
,则getClass
将返回Class<? extends List>
,如Object.getClass
API文档中所述。
答案 1 :(得分:1)
这是因为type erasure。在第一种情况下,您手头有一个实际的具体类型,因此.getClass()
成功。在第二种情况下,obj
的实际类型在运行时被删除,因此.getClass()
不能比Object
做得更好。
具体化的泛型可以解决这个问题。根据{{3}},Java 7中不会出现此功能。该问题也是Alex Miller's blog。
答案 2 :(得分:1)
查看the Javadoc,这是Object.getClass()
的签名:
public final Class<?> getClass()
接着说
实际结果类型是Class&lt;? extends | X |&gt; 其中| X |是擦除 表达式的静态类型 在哪个getClass被调用。
类文字在15.8.2 in the JLS部分中定义。
在第一种情况下,"a".getClass()
的静态类型为String
,因此getClass()
的返回类型为Class<? extends String>
。在第二种情况下,obj
的删除为Object
,因此返回类型为Class<? extends Object>
,实际上只是Class<?>
您可能想知道为什么"a".getClass()
不会返回Class<String>
。毕竟,编译器“知道”“a”是一个String。原因是:当他们Class
通用时,他们认为Class<T>
应该代表T
类型的类,而不是T
的某个子类。 getClass
的签名属于该决定和继承的后果:
<T> Class<? extends Number> getType(Number obj) {
return obj.getClass();
}
如果您致电getType(Long.valueOf(123)
,则会返回Class<? extends Number>
。表达式"a"
是String
类型的对象。为保持一致性,"a".getClass()
必须返回Class<? extends String>
答案 3 :(得分:1)
getClass
的声明返回类型是Class<?>
所以,遗憾的是,编译器只知道getClass
将返回<? extends Object>
的捕获,这与捕获不同<? extends T>
。
来自javadocs:
The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called.
这就是具有显式转换的版本的原因。
在第一个示例中,编译器知道对象的静态类型为String
,因此可以按预期进行捕获。
请注意,您可以执行以下操作:
public static <T extends Number> void f(T obj) {
Class<? extends Number> objClass = obj.getClass();
}
因为我们可以保证T
的静态类型是Number
的子类。
答案 4 :(得分:0)
<? extends T>
表示T的特定子类型,
例如,如果T为Exception
,<? extends T>
可以是RuntimeException
或SQLException
。你永远不会知道T.getClass()是RuntimeException
还是SQLException
。所以需要明确的演员阵容。