你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

JAVA反射之泛型解析

2021/11/29 5:17:41

通常我们使用 Class 来描述数据类型,其实在 JDK 中有一个更通用类型接口 TypeTypeJDK 中所有类型的公共父接口,Class 也是 Type 的其中一个实现类。

public interface Type {
    default String getTypeName() {
        return this.toString();
    }
}

在没有泛型之前,Java 只有原始类型(raw type),此时的类型都通过 Class 进行描述。

public final class Class<T> 
        implements Serializable, GenericDeclaration, Type, AnnotatedElement

加入泛型之后,JDK 对类型进行了扩充,在 Class 之外添加了以下四种类型。

类型描述
ParameterizedType参数化类型,即常说的泛型,例如:List<String>Map<Integer, String>
GenericArrayType泛型数组类型,例如:T[]
TypeVariable类型变量类型,例如:List<T> 中的 T
WildcardType通配符类型,并不是 JAVA 类型,而是泛型表达式,例如:?? super T? extends T

ParameterizedType 的用法

ParameterizedType 表示参数化类型,所谓参数指的就是 <> 中的泛型。

public interface ParameterizedType extends Type {
    // 获取 <> 内的泛型类型
    Type[] getActualTypeArguments();
    // 获取原始类型,如果泛型结构为 O<T>,返回 O
    Type getRawType();
    // 如果泛型结构为 O<T>.I<S>,返回外层的 O<T>
    Type getOwnerType();
    
}

获取父类的泛型信息

Class 类中有一个 getGenericSuperclass() 方法,用于获取带泛型信息的父类,如果父类不带泛型,则等同于 getSuperclass() 方法。

创建一个不带泛型的父类并实现

public class GenericService {
}

public class UserService extends GenericService {
}
public class GenericTest {

    public static void main(String[] args) {
        Type genericSuperClass = UserService.class.getGenericSuperclass();
        Class<? super UserService> superclass = UserService.class.getSuperclass();
        System.out.println(genericSuperClass);
        System.out.println(superclass);
        System.out.println(genericSuperClass == superclass);
    }

}

输出如下

class test.GenericService
class test.GenericService
true

可以看到 getGenericSuperclassgetSuperclass 返回的都是 Class,而且是同一个 Class

接下来使用泛型,再次验证,这里需要两个类 UserRepositoryUser,自行创建即可。

public class GenericService<T, M> {
}

public class UserService extends GenericService<UserRepository, User> {
}

再次运行,可以看到两者返回的对象已经不一样了,getGenericSuperclass 方法返回的是带了泛型信息的 ParameterizedType

test.GenericService<test.UserRepository, test.User>
class test.GenericService
false

通过 ParameterizedType 可以进一步获取到泛型

public class GenericTest {

    public static void main(String[] args) {
        Type genericSuperClass = UserService.class.getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperClass;
        // 获取原始类型 Class
        displayType(parameterizedType.getRawType());
        // 获取泛型
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        for (Type argument : actualTypeArguments) {
            displayType(argument);
        }
    }

    public static void displayType(Type type) {
        System.out.println(type.getTypeName() + " --- " + type.getClass().getSimpleName());
    }

}

输出结果

test.GenericService --- Class
test.UserRepository --- Class
test.User --- Class

获取接口的泛型信息

Class 类中还提供了一个 getGenericInterfaces() 方法,用于获取带泛型信息的接口。

创建两个接口,一个不带泛型,一个带泛型

public interface IA {
}

public interface IB<T, P extends Serializable> {
}

创建一个实现类

public class Impl implements IA, IB<UserRepository, User> {
}

获取接口的泛型


public class GenericTest {

    public static void main(String[] args) {
        Type[] genericInterfaces = Impl.class.getGenericInterfaces();
        for (Type type : genericInterfaces) {
            if (type instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                displayType(parameterizedType);
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                for (Type argument : actualTypeArguments) {
                    displayType(argument);
                }
            } else {
                displayType(type);
            }
            System.out.println("-------------------------------");
        }
    }

    public static void displayType(Type type) {
        System.out.println(type.getTypeName() + " --- " + type.getClass().getSimpleName());
    }

}

输出结果

test.IA --- Class
-------------------------------
test.IB<test.UserRepository, test.User> --- ParameterizedTypeImpl
test.UserRepository --- Class
test.User --- Class
-------------------------------

提供一个获取父类及接口泛型的工具类

public class ReflectUtils {

    /**
     * 获取父类指定位置的泛型类型
     */
    public static Class<?> getSuperClassGenericType(Class<?> clazz, int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            log.warn(String.format("Warn: %s's superclass not ParameterizedType", clazz.getSimpleName()));
            return Object.class;
        }
        return indexOfGenericType(clazz, (ParameterizedType) genType, index);
    }

    /**
     * 获取指定接口指定位置的泛型类型
     */
    public static Class<?> getInterfaceGenericType(Class<?> clazz, Class<?> target, int index) {
        for (Type genericInterface : clazz.getGenericInterfaces()) {
            if (genericInterface instanceof ParameterizedType) {
                if (((ParameterizedType) genericInterface).getRawType() == target) {
                    return indexOfGenericType(clazz, (ParameterizedType) genericInterface, index);
                }
            } else if (genericInterface == target) {
                log.warn(String.format("Warn: %s's interface not ParameterizedType", clazz.getSimpleName()));
                return Object.class;
            }
        }
        return Object.class;
    }

    public static Class<?> indexOfGenericType(Class<?> clazz, ParameterizedType type, int index) {
        Type[] params = type.getActualTypeArguments();
        if (index >= params.length || index < 0) {
            log.warn(String.format("Warn: Index: %s, Size of %s's Parameterized Type: %s .", index,
                    clazz.getSimpleName(), params.length));
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            log.warn(String.format("Warn: %s not set the actual class on superclass generic parameter",
                    clazz.getSimpleName()));
            return Object.class;
        }
        return (Class<?>) params[index];
    }
}

获取字段的泛型类型

Field 类中提供了一个 getGenericType() 方法,用于获取带泛型信息的字段类型,如果不存在泛型信息,则该方法与 getType() 等效。

public class GenericTest {

    private List<String> list;
    private List unknownList;
    private Map<String, Long> map;
    private Map unknownMap;
    private Map.Entry<String, Long> entry;

    public static void main(String[] args) {
        Field[] fields = GenericTest.class.getDeclaredFields();
        for (Field f : fields) {
            System.out.println(f.getName() + " is ParameterizedType: " + (f.getGenericType() instanceof ParameterizedType));
        }
    }
}

输出如下,可以看到,有没有泛型,不是看类声明有没有泛型,而是看变量声明时有没有带泛型。比如 unknownList 没有声明泛型,那么 getGenericType() 方法返回的就是 Class,而不是 ParameterizedType

list is ParameterizedType: true
unknownList is ParameterizedType: false
map is ParameterizedType: true
unknownMap is ParameterizedType: false
entry is ParameterizedType: true

获取泛型变量的泛型信息

public class GenericTest {

    private List<String> list;
    private List unknownList;
    private Map<String, Long> map;
    private Map unknownMap;
    private Map.Entry<String, Long> entry;

    public static void main(String[] args) {
        Field[] fields = GenericTest.class.getDeclaredFields();
        for (Field f : fields) {
            if (f.getGenericType() instanceof ParameterizedType) {
                System.out.print(f.getName() + "<");
                ParameterizedType genericType = (ParameterizedType) f.getGenericType();
                Type[] typeArguments = genericType.getActualTypeArguments();
                int i = 0;
                for (Type argument : typeArguments) {
                    if (i++ > 0) {
                        System.out.print(",");
                    }
                    System.out.print(argument.getTypeName());
                }
                System.out.println(">");
            }
        }
    }
}

输出如下

list<java.lang.String>
map<java.lang.String,java.lang.Long>
entry<java.lang.String,java.lang.Long>

这里也可以看一下 getOwnerType() 方法的用法

public class GenericTest {

    private List<String> list;
    private List unknownList;
    private Map<String, Long> map;
    private Map unknownMap;
    private Map.Entry<String, Long> entry;

    public static void main(String[] args) {
        Field[] fields = GenericTest.class.getDeclaredFields();
        for (Field f : fields) {
            if (f.getGenericType() instanceof ParameterizedType) {
                ParameterizedType genericType = (ParameterizedType) f.getGenericType();
                System.out.println(f.getName() + " ownerType is " +
                        (genericType.getOwnerType() == null ? "null" : genericType.getOwnerType().getTypeName()));
            }
        }
    }
}

输出如下,可以看到,当泛型结构为 O<T>.I<S> 类型时,调用 getOwnerType() 会返回外层的 O<T>,否则返回空。

list ownerType is null
map ownerType is null
entry ownerType is java.util.Map

获取方法的泛型信息

public class GenericTest {

    public static void main(String[] args) {
        Method[] methods = GenericTest.class.getDeclaredMethods();
        for (Method method : methods) {
            if (method.getName().equals("test")) {
                Type[] genericParameterTypes = method.getGenericParameterTypes();
                for (Type genericParameterType : genericParameterTypes) {
                    if (genericParameterType instanceof ParameterizedType) {
                        System.out.println(genericParameterType.getTypeName());
                    }
                }
            }
        }
    }

    public <T> T test(List<String> l1, List<ArrayList<String>> l2, List<T> l3,
                      List<? extends Number> l4, List<ArrayList<String>[]> l5, Map<Boolean, Integer> l6) {
        return null;
    }
}

输出如下

java.util.List<java.lang.String>
java.util.List<java.util.ArrayList<java.lang.String>>
java.util.List<T>
java.util.List<? extends java.lang.Number>
java.util.List<java.util.ArrayList<java.lang.String>[]>
java.util.Map<java.lang.Boolean, java.lang.Integer>

GenericArrayType 的用法

GenericArrayType 表示泛型数组

public interface GenericArrayType extends Type {
    
    Type getGenericComponentType();
    
}

创建一个泛型类,包含一个泛型数组

public class Holder<T> {

    private T[] arrayData;

    public void test(List<String>[] listArray, T[] values) {}

}
public class GenericTest {

    public static void main(String[] args) {
        Field[] fields = Holder.class.getDeclaredFields();
        for (Field field : fields) {
            if (field.getGenericType() instanceof GenericArrayType) {
                GenericArrayType genericType = (GenericArrayType) field.getGenericType();
                System.out.println(field.getName() + " is " + genericType.getTypeName() +
                        " and componentType is " + genericType.getGenericComponentType().getTypeName());
            }
        }
    }
}

输出如下

arrayData is T[] and componentType is T

TypeVariable 的用法

TypeVariable 表示泛型变量,只要泛型不是具体的类型,比如 <T><E extends T> 都归类为泛型变量。

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
    // 获取变量名
    String getName();
    // 获取原始类型
    D getGenericDeclaration();
    // 获取泛型的继承关系
    Type[] getBounds();
    AnnotatedType[] getAnnotatedBounds();
}

获取方法的返回参数

public class GenericTest {
    public static void main(String[] args) {
        Method[] methods = GenericTest.class.getDeclaredMethods();
        Method method = Arrays.stream(methods)
                .filter(v -> v.getName().equals("testTypeVariable"))
                .findAny().get();

        Type type = method.getGenericReturnType();
        displayType(type);
        TypeVariable typeVariable = (TypeVariable) type;
        System.out.println(typeVariable.getGenericDeclaration());
        displayType(typeVariable.getBounds()[0]);
    }

    public static void displayType(Type type) {
        System.out.println(type.getTypeName() + " --- " + type.getClass().getSimpleName());
    }

    public <T extends User> T testTypeVariable() {
        return null;
    }
}

输出如下

T --- TypeVariableImpl
public test.User test.Test.testTypeVariable()
test.User --- Class

WildcardType 的用法

WildcardType 表示通配符,即 <?> 这种,接口包含两个方法

  • getUpperBounds:通配符格式如 <? extends P> 这种,说明泛型类型继承自 PgetUpperBounds 方法可以获取到 P 的类型
  • getLowerBounds:通配符格式如 <? super C> 这种,说明泛型类型是 C 的超类,getLowerBounds 方法可以获取到 C 的类型
public interface WildcardType extends Type {
    // 向上继承
    Type[] getUpperBounds();
    // 向下继承
    Type[] getLowerBounds();
}

获取方法的参数,获取参数中定义的通配符信息

public class GenericTest {

    public static void main(String[] args) {
        Method[] methods = GenericTest.class.getDeclaredMethods();
        Method method = Arrays.stream(methods)
                .filter(v -> v.getName().equals("testWildcardType"))
                .findAny().get();
        Type[] types = method.getGenericParameterTypes();
        int index = 0;
        for (Type type : types) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type typeArgument = parameterizedType.getActualTypeArguments()[0];
            System.out.println("参数" + ++index + "泛型类型:" + typeArgument.getClass().getSimpleName());

            if (typeArgument instanceof WildcardType) {
                WildcardType wildcardType = (WildcardType) typeArgument;
                for (Type upperType : wildcardType.getUpperBounds()) {
                    System.out.println("  upperType:" + upperType.getTypeName());
                }
                for (Type lowerType : wildcardType.getLowerBounds()) {
                    System.out.println("  lowerType:" + lowerType.getTypeName());
                }
            }
        }
    }

    public <T> void testWildcardType(List<T> l1, List<?> l2, List<? extends T> l3, List<? super Integer> l4) {
    }
}

输出如下

参数1泛型类型:TypeVariableImpl
参数2泛型类型:WildcardTypeImpl
  upperType:java.lang.Object
参数3泛型类型:WildcardTypeImpl
  upperType:T
参数4泛型类型:WildcardTypeImpl
  upperType:java.lang.Object
  lowerType:java.lang.Integer