您的位置 首页 java

JAVA反射之泛型解析

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

 public interface Type {
    default String get TypeName () {
        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 类中有一个 get Generic Superclass() 方法,用于获取带泛型信息的父类,如果父类不带泛型,则等同于 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  

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

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

 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> 这种,说明泛型类型继承自 P getUpperBounds 方法可以获取到 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反射之泛型解析

文章地址:https://www.zhihuclub.com/196792.shtml

关于作者: 智云科技

热门文章

网站地图