Java:如何从泛型类型中获取类文字?

2022-08-31 05:40:53

通常,我看到人们像这样使用类文字:

Class<Foo> cls = Foo.class;

但是,如果类型是通用的,例如List呢?这工作正常,但有一个警告,因为列表应该参数化:

Class<List> cls = List.class

那么为什么不添加一个?好吧,这会导致类型不匹配错误:<?>

Class<List<?>> cls = List.class

我认为这样的东西会起作用,但这只是一个普通的语法错误:

Class<List<Foo>> cls = List<Foo>.class

如何静态获取,例如使用类文本?Class<List<Foo>>

可以用来摆脱在第一个示例中非参数化使用List引起的警告,但我宁愿不这样做。@SuppressWarnings("unchecked")Class<List> cls = List.class

有什么建议吗?


答案 1

由于类型擦除,您不能这样做。

Java泛型只不过是对象转换的语法糖。演示:

List<Integer> list1 = new ArrayList<Integer>();
List<String> list2 = (List<String>)list1;
list2.add("foo"); // perfectly legal

在运行时保留泛型类型信息的唯一实例是 Field.getGenericType() 如果通过反射询问类的成员。

所有这些都是 Object.getClass() 具有此签名的原因:

public final native Class<?> getClass();

重要的部分是.Class<?>

换句话说,从Java Generics FAQ:

为什么具体的参数化类型没有类文本?

因为参数化类型没有确切的运行时类型表示形式。

类文本表示表示表示给定类型的对象。例如,类文本表示表示类型的对象,并且与在对象上调用方法时返回的对象相同。类文本可用于运行时类型检查和反射。ClassString.classClassStringClassgetClassString

参数化类型在编译期间在称为 type 擦除 的过程中转换为字节码时会丢失其类型参数。作为类型擦除的副作用,泛型类型的所有实例化共享相同的运行时表示形式,即相应的原始类型的运行时表示形式。换句话说,参数化类型没有自己的类型表示形式。因此,形成类文字(如 、 和 )是没有意义的,因为不存在这样的对象。只有原始类型具有表示其运行时类型的对象。它被称为 。List<String>.classList<Long>.classList<?>.classClassListClassList.class


答案 2

参数化类型没有 Class 文本,但有正确定义这些类型的 Type 对象。

请参阅 java.lang.reflect.ParameterizedType - http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html

Google的Gson库定义了一个TypeToken类,该类允许简单地生成参数化类型,并使用它来以通用友好的方式规范具有复杂参数化类型的json对象。在您的示例中,您将使用:

Type typeOfListOfFoo = new TypeToken<List<Foo>>(){}.getType()

我打算发布指向TypeToken和Gson类javadoc的链接,但Stack Overflow不会让我发布多个链接,因为我是新用户,您可以使用Google搜索轻松找到它们