Java Type

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

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 能用于反序列化。



目录
相关文章
|
4月前
|
IDE Java 编译器
Java The method compareTo(Integer) in the type解决方法
Java编程过程中,Integer对象(或其它继承自Number类的包装类对象)使用Number包装类内置的compareTo()方法来比较调用对象和参数之间的大小的时候,Java的集成开发环境IDE或编译器给出了提示:The method compareTo(Integer) in the type Integer is not applicable for the arguments (Float)
46 5
|
Dubbo 应用服务中间件
java.io.IOException: invalid constant type: 18
java.io.IOException: invalid constant type: 18
683 0
java.io.IOException: invalid constant type: 18
java.lang.Error: Unresolved compilation problem: The type List is not generic; it cannot be parame
java.lang.Error: Unresolved compilation problem: The type List is not generic; it cannot be parame
|
3月前
|
Java 应用服务中间件
已解决:An error occurred at line: 1 in the generated java file The type java.io.ObjectInputStream canno
已解决:An error occurred at line: 1 in the generated java file The type java.io.ObjectInputStream canno
71 0
|
4月前
|
Java 程序员
Java中的强制类型转换(Explicit Type Casting)
Java中的强制类型转换(Explicit Type Casting)
88 0
|
4月前
|
存储 Java 程序员
Java中的自动类型转换(Automatic Type Conversion)
Java中的自动类型转换(Automatic Type Conversion)
111 0
|
4月前
|
Java Maven
idea执行maven打包失败:java.lang.TypeNotPresentException: Type org.springframework.boot.maven.RepackageMojo
idea执行maven打包失败:java.lang.TypeNotPresentException: Type org.springframework.boot.maven.RepackageMojo
219 0
|
Java Spring 容器
No qualifying bean of type ‘java.lang.String‘ available: expected at least 1 bean which qualifies
No qualifying bean of type ‘java.lang.String‘ available: expected at least 1 bean which qualifies
888 0
No qualifying bean of type ‘java.lang.String‘ available: expected at least 1 bean which qualifies
|
11月前
|
JSON Cloud Native Java
猫头虎博主解析:Spring中的“Unknown return value type: java.lang.Boolean“问题
猫头虎博主解析:Spring中的“Unknown return value type: java.lang.Boolean“问题
84 0
|
11月前
|
XML 数据格式
解决 Cannot convert value of type ‘java.lang.String‘ to required type ‘java.sql.Driver‘ for property ‘
解决 Cannot convert value of type ‘java.lang.String‘ to required type ‘java.sql.Driver‘ for property ‘
217 0