java中类型参数的类名?

时间:2011-11-07 17:42:09

标签: java

假设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)
}

3 个答案:

答案 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

但这是另一个故事;)