CoderLi

V1

2022/05/15阅读:15主题:兰青

Java Type

Type 体系

截屏2022-05-08下午4.56.37
截屏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 Stringextends 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[0instanceof 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<Textends T1<List<T>> {
}
public class T3 extends T2<Map<String,Integer>> {
}

简化之后类似如上、我们怎么在 T1 中获取到正确的 Type 类型、且该 Type 能用于反序列化。

分类:

后端

标签:

Java

作者介绍

CoderLi
V1