Java通过反射获取泛型类型信息

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java通过反射获取泛型类型信息相关的知识,希望对你有一定的参考价值。

概述

通常泛型在如下几种情况下使用:

  • 含有泛型的类
// 格式
修饰符 class 类名<代表泛型的变量> { }

// 实例
public class ArrayList<E> {
    public boolean add(E e){ }

    public E get(int index){ }
}
  • 含有泛型的方法
// 格式
修饰符 <代表泛型的变量> 返回值类型 方法参数(参数) { }

// 实例
public class MyGenericClass {
    public <ABC> void print(ABC abc) {
        System.out.println(abc);
    }
}
  • 含有泛型的接口
// 格式
修饰符 interface 接口名<代表泛型的变量> { }

// 实例
public interface MyGenericInterface<E> {
    public abstract void add(E e);

    public abstract E getE();
}

泛型的使用场景就是如上三种,当在类或接口中定义了泛型后,就可以在类或接口中的成员变量、方法参数、方法返回值中也使用泛型;当定义了含有泛型的方法后,就可以在该方法的方法参数、方法返回值和方法内局部变量中使用泛型。

反射获取泛型的场景

在Java中可以通过反射获取泛型信息的场景有如下三个:

  • (1)成员变量的泛型
  • (2)方法参数的泛型
  • (3)方法返回值的泛型

在Java中不可以通过反射获取泛型信息的场景有如下两个:

  • (1)类或接口声明的泛型
  • (2)局部变量的泛型

实例

我们先创建一个类,该类中正好有含有泛型的成员变量、含有泛型的方法返回值、含有泛型的方法参数。代码如下:

class MyClass {
    // 带有泛型的成员变量
    public List<Object> list = new ArrayList<>();

    // 方法返回值中带有泛型
    public List<Object> getList() {
        return list;
    }

    // 方法参数带有泛型
    public void setList(List<Object> list) {
        this.list = list;
    }
}

要获取泛型信息,必须要注意ParameterizedType类,该类中的getActualTypeArguments()方法可以有效获取泛型信息。

具体的实例代码如下:

public class Demo {
    public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
        // 获取成员方法返回值的泛型类型信息
        getMethodReturnValueGeneric();

        System.out.println("======================================");

        // 获取成员变量的泛型类型信息
        getMemberVariablesGeneric();

        System.out.println("======================================");

        // 获取成员方法参数的泛型类型信息
        getMethodParametricGeneric();
    }

    /**
     * 获取方法返回值的泛型类型信息
     *
     * @throws NoSuchMethodException
     */
    public static void getMethodReturnValueGeneric() throws NoSuchMethodException {
        // 获取名为"getList"的方法,在MyClass类中
        Method getListMethod = MyClass.class.getMethod("getList");
        // 获取返回值类型,getGenericReturnType()会返回值带有泛型的返回值类型
        Type genericReturnType = getListMethod.getGenericReturnType();
        // 但我们实际上需要获取返回值类型中的泛型信息,所以要进一步判断,即判断获取的返回值类型是否是参数化类型ParameterizedType
        if (genericReturnType instanceof ParameterizedType) {
            // 如果要使用ParameterizedType中的方法,必须先强制向下转型
            ParameterizedType type = (ParameterizedType) genericReturnType;
            // 获取返回值类型中的泛型类型,因为可能有多个泛型类型,所以返回一个数组
            Type[] actualTypeArguments = type.getActualTypeArguments();
            // 循环数组,遍历每一个泛型类型
            for (Type actualTypeArgument : actualTypeArguments) {
                Class typeArgClass = (Class) actualTypeArgument;
                System.out.println("成员方法返回值的泛型信息:" + typeArgClass);
            }
        }
    }

    /**
     * 获取类中成员变量的泛型类型信息
     *
     * @throws NoSuchFieldException
     */
    public static void getMemberVariablesGeneric() throws NoSuchFieldException {
        // 获取MyTestClass类中名为"list"的字段
        Field listField = MyClass.class.getField("list");
        // 获取该字段的类型信息,getGenericType()方法能够获取带有泛型的类型信息
        Type genericType = listField.getGenericType();
        // 但我们实际上需要获取返回值类型中的泛型信息,所以要进一步判断,即判断获取的返回值类型是否是参数化类型ParameterizedType
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            // 获取成员变量的泛型类型信息
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                Class fieldArgClass = (Class) actualTypeArgument;
                System.out.println("成员变量的泛型信息:" + fieldArgClass);
            }
        }
    }

    /**
     * 获取方法参数的泛型类型信息
     *
     * @throws NoSuchMethodException
     */
    public static void getMethodParametricGeneric() throws NoSuchMethodException {
        // 获取MyTestClass类中名为"setList"的方法
        Method setListMethod = MyClass.class.getMethod("setList", List.class);
        // 获取该方法的参数类型信息(带有泛型)
        Type[] genericParameterTypes = setListMethod.getGenericParameterTypes();
        // 但我们实际上需要获取返回值类型中的泛型信息,所以要进一步判断,即判断获取的返回值类型是否是参数化类型ParameterizedType
        for (Type genericParameterType : genericParameterTypes) {
            ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
            // 获取成员方法参数的泛型类型信息
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                Class realType = (Class) actualTypeArgument;
                System.out.println("成员方法参数的泛型信息:" + realType);
            }
        }
    }
}
/*打印结果:
    成员方法返回值的泛型信息:class java.lang.Object
    ======================================
    成员变量的泛型信息:class java.lang.Object
    ======================================
    成员方法参数的泛型信息:class java.lang.Object
 */

以上是关于Java通过反射获取泛型类型信息的主要内容,如果未能解决你的问题,请参考以下文章

Java使用反射来获取成员变量泛型信息

java 反射和泛型-反射来获取泛型信息

注解和反射反射获取泛型反射获取注解

java通过反射获取私有的构造方法,及反射擦除泛型数据类型约束

C#关于反射创建泛型类

JAVA反射问题,一个方法类的参数能否通过设置成泛型或者啥来接收反射的CLASS。