假设T为类类型参数,为什么我不能使用T.class
我正在编写一个下载页面并根据传递的类解析它的函数。
对于解析,我使用另一个签名为ParseObject::parse(Class<T> classname)
<T> void downloadParse(){
ParseObject obj;
obj.parse(T.class); //<--- why compiler error here?? (whereas something like Integer.class is allowed)
}
答案 0 :(得分:16)
Java泛型通过type erasure实现。它们只能用于编译时检查。在编译之后,对象变为最低的公共对象。 (在本例中为Object.class)。
编译后的字节码不知道T是什么。
如果要访问该类,则需要将方法更改为:
<T> void downloadParse(Class<T> cls){
ParserObject obj;
obj.parse(cls);
}
答案 1 :(得分:2)
Erasure是这里的恶棍。来自Java教程:
例如,Box被转换为Box类型,它被称为 原始类型 - 原始类型是没有的泛型类或接口名称 任何类型的参数。这意味着你无法找出什么类型的 泛型类在运行时使用的对象。以下操作 是不可能的:
public class MyClass<E> { public static void myMethod(Object item) { if (item instanceof E) { //Compiler error ... } E item2 = new E(); //Compiler error E[] iArray = new E[10]; //Compiler error E obj = (E)new Object(); //Unchecked cast warning } }
以粗体显示的操作在运行时没有意义,因为 编译器删除有关实际类型参数的所有信息 (在编译时由类型参数E表示)。
使用Erasure,类型信息被删除,一切都只是一个对象:
当实例化泛型类型时,编译器会对它们进行转换 通过一种称为类型擦除的技术来进行类型化 - 一种过程 编译器删除与类型参数和类型相关的所有信息 类或方法中的参数。类型擦除启用Java 使用泛型来维护二进制兼容性的应用程序 在泛型之前创建的Java库和应用程序。
然后编译器重新引入类“T”作为需要的任何地方的转换。 T不会在泛型中“存在”,因此您无法创建类T的对象。在调用和调出泛型时,编译器将对象强制转换为“T”类。
Google“java erasure”,了解有关其工作原理的更多信息。维基百科提供some examples。
答案 2 :(得分:2)
正如其他人所说,这是不可能的。但是因为它是一个没有参数并且返回无效的方法,你会期望T是什么?
偶尔会遇到的事情是:
<T> T foo(Class<T> cls) {
Object o = ...;
return cls.cast(o);
}
// usage - perfectly type safe
String s = foo(String.class);
此外,有时可能会获得泛型类型参数,例如:这里:
class Foo implements Iterable<String> {
// snip
}
ParameterizedType pt = (ParameterizedType) Foo.class.getGenericInterfaces()[0];
System.out.println(pt); // prints java.lang.Iterable<java.lang.String>
Class<?> at = (Class<?>) pt.getActualTypeArguments()[0];
System.out.println(at.getName()); // prints java.lang.String
但这是另一个故事;)