Javagenerics – 获取实际类型的generics参数

我已经阅读了Java中带有reflection帖的通用参数的Get类型,这让我想知道如何做到这一点。 我使用了有人发布并使用代码的解决方案

List l = new ArrayList(); Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 

然而,这对我来说不起作用

 java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class 

如果我删除了类转换,实际参数的类型是E ,它是List接口的类型定义。

因此,我的问题是,我在这里做错了吗? 这种行为无论如何都是我所期望的,因为这些类型应该在编译期间被删除,对吗?

您使用的代码仅适用于某些特定情况,其中实际类型参数在编译时已知(并存储)。

例如,如果你这样做:

 class IntegerList extends ArrayList {} List l = new IntegerList(); 

在这种情况下,您显示的代码实际上将返回Integer.class ,因为Integer被“烘焙”到IntegerList

一些库(ab)通过使用类型令牌来使用此技巧。 例如,参见GSON类TypeToken

表示generics类型T 您可以使用此类来获取类的generics类型。 >例如,要获取Collection的generics类型,您可以使用:

 Type typeOfCollectionOfFoo = new TypeToken>(){}.getType() 

这是有效的,因为在这里创建的匿名类已经编译了其类型参数为Collection

请注意,这不起作用(即使TypeToken类不会通过使其构造函数受到保护而阻止它):

 Type typeOfCollectionOfFoo = new TypeToken>().getType() 

javadoc会告诉你你在做什么。

Class#getGenericSuperclass()状态

返回表示此Class表示的实体(类,接口,基本类型或void)的直接超类的Type。

如果超类是参数化类型,则返回的Type对象必须准确反映源代码中使用的实际类型参数。 […]

ArrayList的直接超类是AbstractList 。 声明在源代码中是这样的

 public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, java.io.Serializable 

因此,如果您打印出它返回的Type对象,您将看到

 java.util.AbstractList 

因此, ParameterizedType#getActualTypeArguments()表明

返回Type对象的数组,表示此类型的实际类型参数。

将返回Type

 E 

因为EArrayList类定义中使用的实际类型参数。

您描述的方法仅在通用类型由于inheritance而设置时才起作用,因为它在编译期间已知:

  public class SomeClass{ } public class SpecificClass extends SomeClass{ } 

对于此示例,您可以使用该方法,然后您将返回“String.class”。

如果您正在动态创建实例它将无法工作:

 SomeClass s = new SomeClass(); //wont work here. 

一些常见的工作是,将实际的类作为参数传递给以后参考:

  public class SomeClass{ Class clazz public SomeClass(Class clazz){ this.clazz = clazz; } public Clazz getGenericClass(){ return this.clazz; } } 

用法:

  SomeClass someClass= new SomeClass(String.class); System.out.println(someClass.getGenericClass()) //String.class 

实际上你甚至不需要Generic类型来实现这样的场景,因为Java会做同样的事情,就好像你将“T”作为Object处理一样。 唯一的好处是,您可以定义getter和Setter of T,并且不需要一直强制对象。 (因为Java正在为你做这件事)(它被称为Type Erasure)