龙空技术网

JAVA反射之泛型解析

死牛胖子 257

前言:

眼前各位老铁们对“反射与泛型java”大约比较关切,姐妹们都需要知道一些“反射与泛型java”的相关资讯。那么小编同时在网上收集了一些有关“反射与泛型java””的相关文章,希望看官们能喜欢,我们快快来学习一下吧!

通常我们使用 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.GenericServiceclass test.GenericServicetrue

可以看到 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.GenericServicefalse

通过 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 --- Classtest.UserRepository --- Classtest.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> --- ParameterizedTypeImpltest.UserRepository --- Classtest.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: trueunknownList is ParameterizedType: falsemap is ParameterizedType: trueunknownMap is ParameterizedType: falseentry 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 nullmap ownerType is nullentry 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 --- TypeVariableImplpublic 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

标签: #反射与泛型java