通过反射获取泛型信息

1,633 阅读2分钟

Type类

Type是Java所有类型的父接口,它包含Class类型(普通Class类),参数化类型(泛型,带<>的类),数组类型(数组,如String[],Object[]等),还有参数化类型(泛型类<>里面的类型,如K,V,泛指任何类)和基本类型(int,long,float等基本类型)。

Type类的子接口

根据上面Type类的描述,Type被分为几类,就对应了几个不同的子接口:

Class

包含了普通类和基本类型。

ParameteredType

泛型类,含有<>泛型信息的类。

public interface ParameterizedType extends Type {

    // 获取泛型类内部的类型,即<>里面的类型,如Map<K,V>就得到了K和V的类型数组;
    Type[] getActualTypeArguments();

    // 获取原始类型,即去掉<>的类型,如Map<K,V>就得到了Map类型;
    Type getRawType();

    // 获取宿主类型,如果此泛型类定义在子类,该方法获取到的是父类的类型;
    Type getOwnerType();
}

TypeVariable

参数类型,泛指任何类,如Map中的K和V;

public interface TypeVariable<D extends GenericDeclaration> extends Type/*, AnnotatedElement*/ {
    // 获取类型的上边界
    Type[] getBounds();

    // GenericDeclaration的子类是Method,Class,Constructor等,该方法就是获取此类型所声明的地方
    D getGenericDeclaration();

    // 获取类型的名称
    String getName();

}

WildcardType

代表通配符表达式,或泛型表达式,比如<? extends T> <? super T>

public interface WildcardType extends Type {
    
    // 获取限制类型的上边界
    Type[] getUpperBounds();
    
    //获取限制类型的下边界
    Type[] getLowerBounds();

}

GenericArrayType

代表泛型类型数组,如T[],其中T是TypeVariable类型。

public interface GenericArrayType extends Type {
    
    // 数组中的元素类型
    Type getGenericComponentType();
}

通过反射获取类型信息

我通过写一个测试例子来说明以上所有Type的子类型,主要有几个步骤:

  1. 声明一个类,在类中声明一个方法,方法的参数包含以上描述的Type的5中类型;
  2. 通过反射获取该方法的所有包含泛型的参数类型列表:Method.getGenericParameterTypes(Method也有一个接口getParameterTypes获取的是不包含泛型的参数类型列表,即会去除<>信息);
  3. 遍历getGenericParameterTypes获取到的Type数组,针对每个Type元素就可识别出是哪一种子类型;
  4. 从getGenericParameterTypes获取到的Type元素,可调用getActualTypeArguments接口获取泛型类<>里面的类型列表,如果<>又有泛型,可层层递归获取到最终的非泛型类型;

代码例子:

public class ParameterizeTest {

    @Test
    public void test() {

        Method[] methods = ParameterizeTest.class.getMethods();
        Method tMethod = null;
        for (Method method : methods) {
            if ("invokeParameter".equals(method.getName())) {
                tMethod = method;
            }
        }
        // getParameterTypes获取到的是不包含泛型信息的类型,这里是为了和getGenericParameterTypes对比
        Type[] commonTypes = tMethod.getParameterTypes();
        for (Type type : commonTypes) {
            System.out.println("CommonType = " + type + ", ParamTypeCategory = " + type.getClass().getSimpleName());
        }
        System.out.println();

        // getGenericParameterTypes获取到的是包含泛型信息的类型
        Type[] genericTypes = tMethod.getGenericParameterTypes();
        for (Type type : genericTypes) {
            System.out.println("ParamType = " + type + ", ParamTypeCategory = " + type.getClass().getSimpleName());
            if (type instanceof ParameterizedType) {
                Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
                for (int i = 0; i < actualTypes.length; i++) {
                    Type aType = actualTypes[i];
                    System.out.println("\t" + i + " actualType = " + aType + ", actualTypeCategory = " + aType.getClass().getInterfaces()[0].getName());
                    if (aType instanceof WildcardType) {
                        Type[] lower = ((WildcardType) aType).getLowerBounds();
                        Type[] upper = ((WildcardType) aType).getUpperBounds();
                        System.out.println("\t\tLowerBounds = " + Arrays.toString(lower) + ", UpperBounds = " + Arrays.toString(upper));
                    } else if (aType instanceof TypeVariable) {
                        Type[] bounds = ((TypeVariable<?>) aType).getBounds();
                        String name = ((TypeVariable<?>) aType).getName();
                        GenericDeclaration declaration = ((TypeVariable<?>) aType).getGenericDeclaration();
                        System.out.println("\t\tName = " + name + ", Declaration = " + declaration + ", Bounds = " + Arrays.toString(bounds));
                    } else if (aType instanceof ParameterizedType) {
                        System.out.println("\t\tRawType = " + ((ParameterizedType) aType).getRawType() + ", OwnerType = " + ((ParameterizedType) aType).getOwnerType()
                                + ", ActualTypeArguments = " + Arrays.toString(((ParameterizedType) aType).getActualTypeArguments()));
                    }
                }
            } else if (type instanceof GenericArrayType) {
                System.out.println("\t\tGenericComponentType = " + ((GenericArrayType) type).getGenericComponentType());
            }
        }
    }

    public <T, K extends String, V> void invokeParameter(String a0, Map<K, V> a1, List<List<T>> a2, List<? super String> a3, T[] a4, String[] a5) {

    }
}

运行结果:

CommonType = class java.lang.String, ParamTypeCategory = Class
CommonType = interface java.util.Map, ParamTypeCategory = Class
CommonType = interface java.util.List, ParamTypeCategory = Class
CommonType = interface java.util.List, ParamTypeCategory = Class
CommonType = class [Ljava.lang.Object;, ParamTypeCategory = Class
CommonType = class [Ljava.lang.String;, ParamTypeCategory = Class

ParamType = class java.lang.String, ParamTypeCategory = Class
//ParameterizedTypeImpl是ParameterizedType的实现类
ParamType = java.util.Map<K, V>, ParamTypeCategory = ParameterizedTypeImpl是
	0 actualType = K, actualTypeCategory = java.lang.reflect.TypeVariable
		Name = K, Declaration = public void com.example.myapplication.ParameterizeTest.invokeParameter(java.lang.String,java.util.Map,java.util.List,java.util.List,java.lang.Object[],java.lang.String[]), Bounds = [class java.lang.String]
	1 actualType = V, actualTypeCategory = java.lang.reflect.TypeVariable
		Name = V, Declaration = public void com.example.myapplication.ParameterizeTest.invokeParameter(java.lang.String,java.util.Map,java.util.List,java.util.List,java.lang.Object[],java.lang.String[]), Bounds = [class java.lang.Object]
ParamType = java.util.List<java.util.List<T>>, ParamTypeCategory = ParameterizedTypeImpl
	0 actualType = java.util.List<T>, actualTypeCategory = java.lang.reflect.ParameterizedType
		RawType = interface java.util.List, OwnerType = null, ActualTypeArguments = [T]
ParamType = java.util.List<? super java.lang.String>, ParamTypeCategory = ParameterizedTypeImpl
	0 actualType = ? super java.lang.String, actualTypeCategory = java.lang.reflect.WildcardType
		LowerBounds = [class java.lang.String], UpperBounds = [class java.lang.Object]
ParamType = T[], ParamTypeCategory = GenericArrayTypeImpl
		GenericComponentType = T
ParamType = class [Ljava.lang.String;, ParamTypeCategory = Class