Java如何获取泛型类型

参考:我眼中的Java-Type体系(1)
我眼中的Java-Type体系(2)
秒懂Java类型(Type)系统
Java 运行时如何获取泛型参数的类型
Java类型Type 之 ParameterizedType,GenericArrayType,TypeVariabl,WildcardType

从实现的接口获取泛型参数

定义一个泛型父类:

public interface SuperClass<P> {
    String process(P p);
}

实现类1:

public class OneImpl implements SuperClass<House> {

    @Override
    public String process(House house) {
        return null;
    }
}

测试一下:

    public static void main(String[] args) throws Exception {
        SuperClass superClass = new OneImpl();
        // 获取运行时类型
        System.out.println(superClass.getClass());
        // 获取实现的接口
        Type[] types = superClass.getClass().getGenericInterfaces();
        for (Type t : types) {
            // ParameterizedType 的实现类:ParameterizedTypeImpl
            System.out.println("ParameterizedTypeImpl: " + t.getClass().getName());
            // 带有泛型信息
            System.out.println(t);
            System.out.println(t instanceof ParameterizedType);
            // 获取声明这个泛型的类或接口
            System.out.println(((ParameterizedType) t).getRawType());
            // 获取泛型中的实际类型,可能存在多个泛型,比如 SuperClass,所以会返回 Type[] 数组
            Type[] paramGenericTypes = ((ParameterizedType) t).getActualTypeArguments();
            for (Type actualType : paramGenericTypes) {
                // 得到泛型的实际类型,这里也就得到了 Class 类型
                System.out.println("actualTypeName: " + actualType.getClass().getName());
                System.out.println(actualType);
            }
        }

        System.out.println("------------------------------");
        // 获取实现的接口
        Class[] t = superClass.getClass().getInterfaces();
        for (Class c : t) {
            System.out.println(c);

        }
    }

输出:
class com.jiaobucong.common.core.generic.OneImpl
ParameterizedTypeImpl: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
com.jiaobucong.common.core.generic.SuperClass<com.jiaobucong.common.core.generic.House>
true
interface com.jiaobucong.common.core.generic.SuperClass
actualTypeName: java.lang.Class
class com.jiaobucong.common.core.generic.House
------------------------------
interface com.jiaobucong.common.core.generic.SuperClass

实现类2,不带泛型:

public class TwoImpl implements SuperClass {
    @Override
    public String process(Object o) {
        return null;
    }
}

来看测试:

  public static void main(String[] args) throws Exception {
       SuperClass superClass1 = new TwoImpl();
        Type[] types1 = superClass1.getClass().getGenericInterfaces();
        for (Type type : types1) {
            System.out.println(type);
            // 实现类没有指定泛型参数,没有对应的 ParameterizedTypeImpl 实现类
            System.out.println(type instanceof ParameterizedType);
        }
  }

输出:
interface com.jiaobucong.common.core.generic.SuperClass
false

通过 Method 方法级获取泛型参数

public class GenericArrayTest {

    public static void main(String[] args) throws Exception {
        Method[] methods = OneGenericClass.class.getMethods();
        for (Method method : methods) {
            // 获取每个方法的参数化类型
            if (!"go".equals(method.getName())) {
                continue;
            }
            Type[] parameters = method.getGenericParameterTypes();
            for (Type type : parameters) {
                // 不同的参数定义返回的类型也是不一样的
                if (type instanceof Class) {
                    // 第一个参数
                    System.out.println("class: " + type);
                } else if (type instanceof ParameterizedType) {
                    // 声明这个泛型的类
                    Class<?> clazz = (Class<?>) ((ParameterizedType) type).getRawType();
                    System.out.println(type + ", ParameterizedType, "
                            + "holderType: " +  clazz
                            + ", actual parameterized classes: "
                            + Arrays.toString(getActualClass(type)));
                } else if(type instanceof GenericArrayType) {
                    // 对于数组类型得到的是 GenericArrayType
                    Type arrayType = ((GenericArrayType) type).getGenericComponentType();
                    System.out.println(type + ", GenericArrayType, actual classes: "
                            + Arrays.toString(getActualClass(arrayType)));
                }
            }
        }

    }

    public static Class<?>[] getActualClass(Type type) {
        if (type instanceof ParameterizedType) {
            Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
            Class<?>[] actualClasses = new Class[actualTypes.length];
            for (int i = 0; i < actualTypes.length; i++) {
                Type actualType = actualTypes[i];
                if (actualType instanceof Class) {
                    actualClasses[i] = (Class<?>) actualType;
                }
                // ArrayList> arrayLists, 第一次获取到的类型还是 ParameterizedType 类型
                if (actualType instanceof ParameterizedType) {
                    return getActualClass(actualType);
                }
            }
            return actualClasses;
        }
        return null;
    }


    class OneGenericClass {

        public void go(long userId, ArrayList<ArrayList<String>> arrayLists, List<Long> orderIds, Map<String, Integer> map, List<Long>[] listArr) {
            System.out.println(userId);
            System.out.println(orderIds);
        }
    }
    
输出:
class: long
java.util.ArrayList<java.util.ArrayList<java.lang.String>>, ParameterizedType, holderType: class java.util.ArrayList, actual parameterized classes: [class java.lang.String]
java.util.List<java.lang.Long>, ParameterizedType, holderType: interface java.util.List, actual parameterized classes: [class java.lang.Long]
java.util.Map<java.lang.String, java.lang.Integer>, ParameterizedType, holderType: interface java.util.Map, actual parameterized classes: [class java.lang.String, class java.lang.Integer]
java.util.List<java.lang.Long>[], GenericArrayType, actual classes: [class java.lang.Long]

从 Field 获取泛型参数

public class GenericTest1 {
    private List<String>[] listArray;
    private List<Long> list;

    public static void main(String[] args) throws Exception {
        test1();
        System.out.println("-------------------test2");
        test2();
    }

    public static void test1() throws Exception {
        Field fieldListArray = GenericTest1.class.getDeclaredField("listArray");
        Type type = fieldListArray.getGenericType();
        // 这里会报错,得到的不是一个 ParameterizedType
//        Type[] arrayType = ((ParameterizedType) type).getActualTypeArguments();
        // 得到的是一个GenericArrayType,这个地方是一个泛型数组的类型,所以得到的是 GenericArrayType
        // 得到的类型是去掉了最右边的[],是 List,得到的 arrayType 是 ParameterizedType
        Type arrayType = ((GenericArrayType) type).getGenericComponentType();
        System.out.println(arrayType);
        System.out.println(arrayType.getClass().getName());
        Type[] types = ((ParameterizedType) arrayType).getActualTypeArguments();
        for (Type type1 : types) {
            System.out.println(type1.getClass().getName());
            // 这里获取到了 List[] listArray <> 中的 String 类型
            System.out.println(type1);
        }
    }

    public static void test2() throws Exception {
        Field fieldList = GenericTest1.class.getDeclaredField("list");
        Type typeList = fieldList.getGenericType();
        System.out.println(typeList.getClass().getName());
        Type[] parameterTypes = ((ParameterizedType) typeList).getActualTypeArguments();
        // 获取 List 中的 T 类型
        for (Type type : parameterTypes) {
            System.out.println(type.getClass().getName());
            System.out.println(type);
        }

        // 定义这个 List 的类型
        System.out.println(fieldList.getType());
    }
}

输出:
java.util.List<java.lang.String>
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.lang.Class
class java.lang.String
-------------------test2
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.lang.Class
class java.lang.Long
interface java.util.List

我们可以在类接口上、构造器上、方法上定义泛型类型,不同的泛型参数定义得到可能是 ParameterizedType、TypeVariable、Class、GenericArrayType,然后再通过得到的类型做不同的处理。

你可能感兴趣的:(Java零碎)