获取泛型实际类型

young 1,056 2022-07-12

Java反射获取

获取类上的泛型

获取父类定义的泛型

例如现在有一个父类

public abstract class TestClass<E> {
  ......
}

同时他有多个实现类,如

public class TestStringClass extends TestClass<String>{
  ....
}

public class TestIntegerClass extends TestClass<Integer>{
  ....
}
....

此时如果要获取该类上声明的泛型

需要用到Class类中的getGenericSuperclass方法

getGenericSuperclass方法的作用是:

返回该class所表示的实体(类、接口、原始类型或void)的直接父类的Type。如果父类是参数化类型(即有泛型定义),那么返回的Type对象必须准确的反应源代码中使用的实际类型参数。

如果是带有泛型的父类,则会返回ParameterizedType,如果当前Class是Object类,接口,原始类型或者void,则会返回null。

如果此对象表示数组类,则返回表示Object类的Class对象。

ParameterizedType类有3个方法,其中getActualTypeArguments能获取到泛型列表的数组。

那么在父类中,如果要获取子类声明的泛型类型,就可以使用此方法

Type genericSuperclass = this.getClass().getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType){
  ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
  Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
  for (Type actualTypeArgument : actualTypeArguments) {
    System.out.println(actualTypeArgument);
  }
}

如此一来,就可以获取到父类的泛型了。

public abstract class TestClass<E> {

   public void print(){
      Type genericSuperclass = this.getClass().getGenericSuperclass();
      List<Type> list = null;
      if (genericSuperclass instanceof ParameterizedType){
         ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
         Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
         list = Arrays.asList(actualTypeArguments);
      }
      System.out.println(this.getClass() + " 的泛型 = " + list);
   }
}

public class TestStringClass extends TestClass<String>{

    public static void main(String[] args) {
        TestStringClass testStringClass = new TestStringClass();
        testStringClass.print();
    }
}

// class xxx.TestStringClass 的泛型 = [class java.lang.String]

public class TestMapClass extends TestClass<Map<String,String>>{

    public static void main(String[] args) {
        TestMapClass testMapClass = new TestMapClass();
        testMapClass.print();
    }
}

// class xxx.TestMapClass 的泛型 = [java.util.Map<java.lang.String, java.lang.String>]

如果我们想获取泛型中的泛型,例如上面的TestClass<Map<String,String>>中的Map的泛型。

我们可以看到ParameterizedType有很多实现类,其中java原生的实现类为sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl

这个实现类中也有一个actualTypeArguments属性,也就是说,可以继续尝试获取泛型列表

获取接口定义的泛型

很多的接口上也定义了泛型描述,可以通过Class的getGenericInterfaces方法获取,因为一个类可以实现多个接口,所以返回了一个Type数组,可以遍历数组,找到需要处理的接口对应的Type,其余的操作就获取父类上的泛型操作一致了。

获取属性的泛型

获取属性的泛型,先通过Class,获取到需要获取泛型的Field,然后过个Field类的getGenericType方法获取到Type,其余操作与获取父类上的泛型操作一致。

通过Spring工具类获取

spring-core工程中,提供了一个ResolvableType工具类,他可以从属性、方法参数、方法返回、类中后去对应的泛型。从Spring4.0开始提供这个工具类。

常用的方法有

forField(Field field) 获取属性的泛型

forMethodParameter(Method method, int parameterIndex) 获取方法指定参数的泛型

forMethodReturnType(Method method) 获取方法返回值的泛型

forConstructorParameter(Constructor constructor, int parameterIndex) 获取构造函数指定参数的泛型

forClass(Class clazz) 获取class的泛型

forType(Type type) 获取type的泛型

forInstance(Object) 通过实体获取泛型

官方示例:

private HashMap<Integer, List<String>> myMap;
 
  public void example() {
      ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
      t.getSuperType(); // AbstractMap<Integer, List<String>>
      t.asMap(); // Map<Integer, List<String>>
    	// 获取指定下标的泛型类型
      t.getGeneric(0).resolve(); // Integer
      t.getGeneric(1).resolve(); // List
      t.getGeneric(1); // List<String>
    	// 获取指定下标的泛型的指定下标的泛型,即获取嵌套泛型的泛型
      t.resolveGeneric(1, 0); // String
  }