使用反射获取Java中泛型参数的类型

问题

是否有可能获得通用参数的类型?

一个例子:

public final class Voodoo {
    public static void chill(List<?> aListWithTypeSpiderMan) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        Class typeOfTheList = ???;
    }

    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>());
    }
}

#1 热门回答(132 赞)

一个构造,我曾经偶然发现了

Class<T> persistentClass = (Class<T>)
   ((ParameterizedType)getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];

所以似乎有一些反思 - 魔术我不幸地完全不明白...抱歉。


#2 热门回答(117 赞)

我想尝试打破@DerMike的答案来解释:

首先,类型擦除并不意味着运行时的JDKeliminatestype信息。它是一种允许编译时类型检查和运行时类型兼容性以同一种语言共存的方法。正如这段代码所暗示的那样,JDK保留了已删除的类型信息 - 它与被检查的强制转换和东西无关。

其次,这为通用类提供了通用类型信息,这种类型信息恰好是被检查的具体类型的层次上的一级 - 即。具有泛型类型参数的抽象父类可以找到与其类型参数对应的具体类型,以便直接从中获取自身的具体实现。如果这个类是非抽象的并且被实例化,或者具体实现是两个级别,那么这将不起作用(尽管一点点jimmying可以使它适用于超过一个或最低级别的任何预定数量的级别使用X泛型类型参数,等等。

无论如何,关于解释。这里是代码,分为行以便于参考:

1# Class genericParameter0OfThisClass = 
2#     (Class)
3#         ((ParameterizedType)
4#             getClass()
5#                .getGenericSuperclass())
6#                    .getActualTypeArguments()[0];

让'us'成为包含此代码的泛型类型的抽象类。从内到外阅读:

  • 第4行获取当前具体类的Class实例。这标识了我们的直系后代的具体类型。
  • 第5行将该类的超类型作为类型;这是我们。由于我们是参数类型,我们可以安全地将自己投射到ParameterizedType(第3行)。关键是当Java确定此Type对象时,它使用子类中存在的类型信息将类型信息与新ParameterizedType实例中的类型参数相关联。所以现在我们可以访问我们的泛型的具体类型。
  • 第6行按照类代码中的声明顺序获取映射到我们的泛型中的类型数组。对于此示例,我们提取第一个参数。这是一个类型。
  • 第2行将最终的Type转换为Class。这是安全的,因为我们知道我们的泛型类型参数能够采用什么类型,并且可以确认它们都是类(我不确定如何在Java中获取没有类实例的泛型参数)与之相关的,实际上)。

......那就是它。因此,我们将类型信息从我们自己的具体实现推送回自己,并使用它来访问类句柄。我们可以将getGenericSuperclass()加倍并进入两个级别,或者取消getGenericSuperclass()并为自己获取值作为具体类型(警告:我还没有测试过这些场景,它们还没有找到我)。

如果你的具体孩子是一个任意数量的跳跃,或者如果你是具体的而不是最终的,那么它会变得棘手,如果你期望你的(可变深度)孩子有自己的仿制品,那就特别棘手。但是你通常可以围绕这些考虑因素进行设计,因此这可以帮助你完成大部分工作。

希望这有助于某人!我认识到这篇文章很古老。我可能会剪断这个解释并保留其他问题。


#3 热门回答(19 赞)

实际上我让这个工作。请考虑以下代码段:

Method m;
Type[] genericParameterTypes = m.getGenericParameterTypes();
for (int i = 0; i < genericParameterTypes.length; i++) {
     if( genericParameterTypes[i] instanceof ParameterizedType ) {
                Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"

     }
 }

我正在使用jdk 1.6