获取参数化类的类型参数

dru*_*key 7 java reflection

我有一个Foo<T, U>具有以下构造函数的类:

public Foo() {
  clazz = Class<U>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
Run Code Online (Sandbox Code Playgroud)

我在构造函数中做的是获取参数的类U.我需要它,因为我用它来实例化那个类.

问题是,当我的子类Foo不是它的直接sublcass时,它不起作用.让我举一个例子.

我上课了Bar<T> extends Foo<T, Class1>.在这里,Class1不是变量而是类.

我也有课Baz extends Bar<Class2>.Class2也是一个类,而不是变量.

问题是当我尝试实例化Baz(Baz -> Bar<Class2> -> Foo<T, Class2>)时它失败了.我得到一个ArrayIndexOutOfBoundsException因为getActualTypeArguments()返回一个只包含类Class2(大小为1)的数组,我正在尝试获取数组的第二个元素.那是因为我得到的论点Bar<Class2>,而不是Foo 的论点.

我想要的是修改Foo构造函数以某种方式我可以在参数U中获取类,如果我实例化的类是否是直接子类并不重要.我想我应该可以进入类的层次结构,直到达到类Foo,将其转换为ParameterizedType并获取参数,但我找不到如何.

任何的想法?

提前致谢.

Nic*_*ick 3

这是一个很好的方法——它是真正获得在 Java 字节码中编译的通用类型信息的唯一方法。Java 中泛型的其他内容都只是类型擦除。请参阅下面似乎是可行的解决方案。有四种情况:

  1. 相当复杂的继承级别
  2. 您的继承场景
  3. 课程本身(clazz将是null
  4. 不提供实际值的子类 ( clazz = null)

这是代码(Test.java):

import java.lang.reflect.*;
import java.util.*;

class A<T1, T2>
{
  Class<T2> clazz;

  A()
  {
    Type sc = getClass().getGenericSuperclass();
    Map<TypeVariable<?>, Class<?>> map = new HashMap<TypeVariable<?>, Class<?>>();
    while (sc != null)
    {
      if (sc instanceof ParameterizedType)
      {
        ParameterizedType pt = (ParameterizedType) sc;
        Type[] ata = pt.getActualTypeArguments();
        TypeVariable[] tps = ((Class) pt.getRawType())
            .getTypeParameters();
        for (int i = 0; i < tps.length; i++)
        {
          Class<?> value;
          if (ata[i] instanceof TypeVariable)
          {
            value = map.get(ata[i]);
          }
          else
          {
            value = (Class) ata[i];
          }
          map.put(tps[i], value);
        }
        if (pt.getRawType() == A.class)
        {
          break;
        }
        if (ata.length >= 1)
        {
          sc = ((Class) pt.getRawType()).getGenericSuperclass();
        }
      }
      else
      {
        sc = ((Class) sc).getGenericSuperclass();
      }
    }

    TypeVariable<?> myVar = A.class.getTypeParameters()[1];
    clazz = map.containsKey(myVar) ? (Class<T2>) map.get(myVar) : null;
  }
}

class Bar<T> extends A<T, String> {}
class Baz extends Bar<Integer> {}

class A2<T3, T1, T2> extends A<T1, T2> { }
class B<T> extends A2<Long, String, T> { }
class C extends B<Integer> { }
class D extends C { }

class Plain<T1, T2> extends A<T1, T2> {}

public class Test
{
  public static void main(String[] args)
  {
    new D();
    new Baz();
    new A<String, Integer>();
    new Plain<String, Integer>();
  }
}
Run Code Online (Sandbox Code Playgroud)