Type 体系
截屏2022-05-08下午4.56.37
Class
这个我们是最常见的。我们经常会问某个对象/变量是什么类型、我们经常回答都是对应一个具体的 Class
public class ClassMain { private Integer age; private String name; private List<String> alias; public static void main(String[] args) { ClassMain classMain = new ClassMain(); System.out.println("classMain 这个变量的类型:" + classMain.getClass()); Field[] declaredFields = classMain.getClass().getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField.getName() + ":" + declaredField.getType()); } } } 复制代码
classMain 这个变量的类型:class com.example.junitspringboot.type.ClassMain age:class java.lang.Integer name:class java.lang.String alias:interface java.util.List
为啥变量 alias
的输出只有List
而不包含 String
的,这个就是下面要说的内容
ParameterizedType
参数化类型、这个也是我们最常见的。
public interface ParameterizedType extends Type { // 获取实际的参数类型 Type[] getActualTypeArguments(); // 获取原始的类型 Type getRawType(); // 针对内部类、返回其外层的类型 Type getOwnerType(); } 复制代码
从类/成员变量获取
就如上面的例子、alias
的类型就是 parameterizedType 而不是简单的 Class
我们可以通过另一种方法获取 getGenericType
public class ClassMain { private Integer age; private String name; private List<String> alias; public static void main(String[] args) { ClassMain classMain = new ClassMain(); System.out.println("classMain 这个变量的类型:" + classMain.getClass()); Field[] declaredFields = classMain.getClass().getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField.getName() + ":" + declaredField.getGenericType()); } } } 复制代码
// java.lang.reflect.Field#getGenericType public Type getGenericType() { if (getGenericSignature() != null) return getGenericInfo().getGenericType(); else return getType(); } public Class<?> getType() { return type; } 复制代码
可以看到 getType 方法返回的是 Class 而 getGenericType 返回的是 Type 类型
classMain 这个变量的类型:class com.example.junitspringboot.type.ClassMain age:class java.lang.Integer name:class java.lang.String alias:java.util.List<java.lang.String>
我们稍微改下程序
public class ClassMain { private Integer age; private String name; private List<String> alias; public static void main(String[] args) { ClassMain classMain = new ClassMain(); System.out.println("classMain 这个变量的类型:" + classMain.getClass()); Field[] declaredFields = classMain.getClass().getDeclaredFields(); for (Field declaredField : declaredFields) { Type type = declaredField.getGenericType(); if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) { System.out.println(declaredField.getName() + " getActualTypeArguments:" + actualTypeArgument); } System.out.println(declaredField.getName() + " getOwnerType:" + parameterizedType.getOwnerType()); System.out.println(declaredField.getName() + " getRawType:" + parameterizedType.getRawType()); } else if (type instanceof Class) { System.out.println(declaredField.getName() + ":" + type); } } } } 复制代码
classMain 这个变量的类型:class com.example.junitspringboot.type.ClassMain age:class java.lang.Integer name:class java.lang.String alias getActualTypeArguments:class java.lang.String alias getOwnerType:null alias getRawType:interface java.util.List
那方法内的局部变量呢?还有方法的参数呢、他们如果声明变量的时候带有泛型信息、怎么获取得到呢、他们只能使用变量然后调用 getClass 方法、没错、Java 中擦除了、因为 Java 的泛型只是一个语法糖、只保留类、Field、Method 的泛型信息
增加一个内部类的成员变量
static class Holder<T> { private T data; } private Holder<String> holder; 复制代码
holder getActualTypeArguments:class java.lang.String holder getOwnerType:class com.example.junitspringboot.type.ClassMain holder getRawType:class com.example.junitspringboot.type.ClassMain$Holder
可以看到 getOwnerType 不再返回 null 了
从类中获取
public class Msg<T> { private T data; } public class StringMsg extends Msg<String>{ } 复制代码
Type genericSuperclass = StringMsg.class.getGenericSuperclass(); if (genericSuperclass instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; System.out.println(parameterizedType.getRawType()); System.out.println(parameterizedType.getOwnerType()); for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) { System.out.println(actualTypeArgument.getTypeName()); } } 复制代码
class com.example.junitspringboot.type.Msg null java.lang.String
可以看到子类继承 Msg 类的时候传递了 String 作为参数给到父类。让父类成为参数化类型。
从方法中获取
public class StringMsg extends Msg<String>{ List<String> process(){ System.out.println(); return null; } } 复制代码
Method[] declaredMethods = StringMsg.class.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { Type genericReturnType = declaredMethod.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType) { System.out.println(((ParameterizedType) genericReturnType).getActualTypeArguments()[0]); System.out.println(((ParameterizedType) genericReturnType).getRawType()); } } 复制代码
class java.lang.String interface java.util.List
TypeVariable
泛型的类型变量,指的是List< T>、Map< K,V>中的T,K,V等值,实际的Java类型是TypeVariable
static class Holder<T extends String & Serializable> { private T data; public T getData() { return data; } } static class SonHolder<T extends String> extends Holder<T>{ } private static void typeVariable() throws NoSuchFieldException, NoSuchMethodException { Field data = Holder.class.getDeclaredField("data"); Type genericType = data.getGenericType(); if (genericType instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) genericType; System.out.println(typeVariable.getName()); } Method getData = Holder.class.getDeclaredMethod("getData"); Type genericReturnType = getData.getGenericReturnType(); if (genericReturnType instanceof TypeVariable) { TypeVariable typeVariable = (TypeVariable) genericReturnType; System.out.println(typeVariable.getName()); } Type genericSuperclass = SonHolder.class.getGenericSuperclass(); if (genericSuperclass instanceof ParameterizedType) { Type actualTypeArgument = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]; if (actualTypeArgument instanceof TypeVariable) { System.out.println(((TypeVariable) actualTypeArgument).getName()); Type[] bounds = ((TypeVariable) actualTypeArgument).getBounds(); System.out.println(); } } } 复制代码
类型变量的上限可以为多个,必须使用&符号相连接,例如 List< T extends Number & Serializable>;其中,& 后必须为接口;
WildcardType
通配符表达式,或泛型表达式,它虽然是Type的一个子接口,但并不是Java类型中的一种,表示的仅仅是类似 ? extends T、? super K这样的通配符表达式。 ?—通配符表达式,表示通配符泛型,但是WildcardType并不属于Java-Type中的一种
static class Holder<T extends String & Serializable> { private T data; List<?> list; public T getData() { return data; } } private static void wildcardType() throws Exception { Field list = Holder.class.getDeclaredField("list"); Type genericType = list.getGenericType(); if (genericType instanceof ParameterizedType) { Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments(); if (actualTypeArguments[0] instanceof WildcardType) { WildcardType wildcardTypes = (WildcardType) actualTypeArguments[0]; System.out.println(wildcardTypes.getUpperBounds()[0].getTypeName()); } } } 复制代码
GenericArrayType
泛型数组 泛型数组,描述的是形如:A< T>[]或T[]类型变量和原始类型
/** * 含有泛型数组的才是GenericArrayType * @param pTypeArray GenericArrayType type :java.util.List<java.lang.String>[]; * genericComponentType:java.util.List<java.lang.String> * @param vTypeArray GenericArrayType type :T[];genericComponentType:T * @param list ParameterizedType type :java.util.List<java.lang.String>; * @param strings type :class [Ljava.lang.String; * @param test type :class [Lcom.wangji.demo.GenericArrayTypeTest; */ public void testGenericArrayType(List<String>[] pTypeArray, T[] vTypeArray , List<String> list, String[] strings, GenericArrayTypeTest[] test) { } /** * 1、getGenericComponentType * 返回泛型数组中元素的Type类型,即List<String>[] 中的 List<String>(ParameterizedTypeImpl) * 、T[] 中的T(TypeVariableImpl); * 值得注意的是,无论是几维数组,getGenericComponentType()方法都只会脱去最右边的[],返回剩下的值; */ 复制代码
Spring 中的 ResolvableType
建议使用 ResolvableType 、最近封装公司的 RPC 通信模块、子类通过继承的方式将泛型信息传递到父类、这个时候获取到完整的泛型信息显得非常重要、后续 RPC 返回的信息反序列化为对应的实体。
public class T1<T> { } public class T2<T> extends T1<List<T>> { } public class T3 extends T2<Map<String,Integer>> { } 复制代码
简化之后类似如上、我们怎么在 T1 中获取到正确的 Type 类型、且该 Type 能用于反序列化。