【问题标题】:Getting generic parameter from supertype class从超类型类获取泛型参数
【发布时间】:2017-06-29 23:36:18
【问题描述】:

假设我有一个这样的父接口/类

interface Parent<T> {}

以及一些修复泛型类型的实现接口。

interface Child extends Parent<Type> {}

如果我拥有ChildClass 对象,我可以使用反射来获取代表TClass 的实例吗?像这样的:

<T, I extends Parent<T>> I create(Class<I> type) {
    Class<T> tType = ...
    ...
}

目前我将tType 作为参数传入,但如果可以的话,我想简化一下。

【问题讨论】:

    标签: java reflection


    【解决方案1】:

    是的,不管其他人怎么说,如果您有权访问子类的Class 对象,则此信息可用的。您需要使用getGenericSuperclassgetActualTypeArguments

    ParameterizedType superClass = (ParameterizedType)childClass.getGenericSuperclass();
    System.out.println(superClass.getActualTypeArguments()[0]);
    

    在您的示例中,“实际”类型参数应为 Type 返回 Class

    【讨论】:

    • 这适用于直接父类型,但不适用于任何祖先类型。如果有一个内置方法,对于任何T objectClass&lt;? super T&gt; ancestorType,获取objectancestorType 的类型参数,那就太好了。
    • @Daniel,是的,但是使用一点recusion,您应该能够从任何特定的基类派生您想要的任何类型参数。您应该能够创建一个方法,允许您指定未具体化的泛型 Class 和类型参数的索引(对于该泛型类),并从任何子类获取该类型参数的 Class
    【解决方案2】:

    如果您需要在运行时对泛型类型做任何重要的事情,请考虑使用 Guava 的 TypeToken。它可以回答您的问题(以及更多问题!),同时解决评论者提出的一些细微问题:

    private interface Parent<T> {}
    private interface Intermediate<U, V> extends Parent<V> {}
    private interface Child<Z> extends Comparable<Double>, Intermediate<Z, Iterable<String>> {}
    
    public void exploreGuavaTypeTokens() {
        final TypeToken<? super Child> token = TypeToken.of(Child.class).getSupertype(Parent.class);
        final TypeToken<?> resolved = token.resolveType(Parent.class.getTypeParameters()[0]);
        System.out.println(resolved); // "java.lang.Iterable<java.lang.String>"
        final Class<?> raw = resolved.getRawType();
        System.out.println(raw); // "interface java.lang.Iterable"
    }
    

    【讨论】:

      【解决方案3】:

      我不这么认为。阅读type erasure:泛型类型仅用于编译时检查,然后被丢弃。它们不存储在编译的类文件中,因此在运行时不可用。

      【讨论】:

      • 我希望它们在子类型的声明中已修复,因此可以访问。
      • 不。在运行时它实际上只是interface Child extends Parent。我认为编译类中唯一保留的泛型信息是类型参数的名称——例如,您可以通过Parent 接口上的反射获得字符串“T”。
      • 这个答案是错误的。该信息存储在 class 文件中,只是在方法的运行时处理中不可用。见the relevant javadocs
      • 编译时检查使用类文件,你知道(如果没有 JDK 的整个源代码,你怎么能编译一些东西?)
      猜你喜欢
      • 1970-01-01
      • 2013-09-13
      • 2021-07-10
      • 2013-08-15
      • 2018-07-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多