美文网首页
Java Type类型

Java Type类型

作者: 生饼 | 来源:发表于2020-01-23 14:58 被阅读0次

    1 Type接口

    Java中,JVM会为每一个加载到内存中的类型创建一个Class对象。通过Class对象我们可以获取FieldConstructorMethodParameterModifier等几乎所有的类的元数据信息,这就是Java中反射的基础,为Java开发提供了很大的灵活性和通用性,是Java语言的一大亮点。

    但是遇到泛型类(Generic Class)时,Class就不灵光了。在类型擦除(Type erase)后,Class丢失了泛型类型信息。比如,List<Integer>List<String>这两个类型,他们的Class对象是同一个,但是这两个类型又截然不同,这两个类型的变量不能相互赋值,也不能把一个List中的元素存入另一个List

    其实从Java 1.5开始,Java提供了一个Type接口。Type接口是所有类型的公共父接口,包括类和接口(raw types)、参数化类型(parameterized types)、数组类型(array types)、类型变量(type variables)和基本类型(primitive types),可以说,Type是Java语言中的顶级类型接口。Class就实现了Type接口,List<Integer>List<String>两个类型的Type信息是不一样的。

    有了Type类型,Java开发可以更加灵活,可以写出更加通用的代码。

    我们先看看Type接口的定义,它只有一个方法,就是获取Type的字符串名字。

    public interface Type {
    
        default String getTypeName() {
            return toString();
        }
    }
    

    下面这些类和接口实现或扩展了Type接口:

    graph BT
    
    B[Class]-->type[Type]
    C[ParameterizedType]-->type
    D[TypeVariable]-->type
    E[GenericArrayType]-->type
    F[WildcardType]-->type
    
    

    从上图可以看到,除了Class实现了Type接口,还有四个接口(ParameterizedType、TypeVariable、GenericArrayType、WildcardType)扩展了Type接口。

    1.1 Class类

    这个大家已经比较熟了,就不多介绍了。它的getTypeName()返回的内容就是Class的全限定域名(fully qualified domain name,FQDN)

    1.2 ParameterizedType接口

    ParameterizedType接口,跟它的名字一样,参数化类型,表示该类型带有类型参数,比如List<String>这种。它的定义如下:

    public interface ParameterizedType extends Type {
        Type[] getActualTypeArguments();
        Type getRawType();
        Type getOwnerType();
    }
    

    getActualTypeArguments()方法返回实际的参数类型,因为一个类型可以有多个类型参数,所以是一个数组。比如List<String>类型的这个方法返回的是String类的Class对象(还记得Class实现了Type接口吗?)

    getRawType()方法返回擦除类型参数后的类型,比如List<String>类型的这个方法返回的是List类的Class对象

    getOwnerType()方法,如果当前类型定义在另一个类型的内部,则返回外部的类型;否则,则是一个顶层类型(top-level type),返回null。比如List<String>类型的这个方法返回的是null,但是Map.Entry<String, String>类型的这个方法返回的就是Map类的Class对象,因为Entry类定义在Map类的内部

    ParameterizedType接口可能是我们使用的最多的Type子接口,毕竟我们使用Type类型,往往是希望知道类型的泛型参数的具体化后的类型。当然ParameterizedType的泛型参数不一定具体化了,它只是表明这个类型包含类型参数。泛型参数是否具体化,可以通过getActualTypeArguments()方法返回的Type类型是Class类型还是其他Type类型来确定。不过这里还存在一个嵌套的问题,比如List<List<String>>,它的ActualTypeArgumentList<String>,还是一个ParameterizedType

    1.3 TypeVariable接口

    跟它的名字一样,表示这是一个类型变量。比如类型List<T>中的T就是一个TypeVariable。它的定义如下:

    public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
        Type[] getBounds();
        D getGenericDeclaration();
        String getName();
        AnnotatedType[] getAnnotatedBounds();
    }    
    

    通过TypeVariable我们主要通过getBounds()getName()方法获取它的边界和名字。比如List<T extends Person>类型,它的ActualTypeArgumentTypeVariable类型,这个TypeVariable的名字是T,边界是Person Class类型。

    1.4 GenericArrayType接口

    泛型数组类型接口,它的定义如下:

    public interface GenericArrayType extends Type {
        Type getGenericComponentType();
    }
    

    GenericArrayType接口只有一个getGenericComponentType()方法,返回数组元素的类型,如List<String>[]类型返回的结果是List<String>类型,他是一个ParameterizedType

    1.5 WildcardType接口

    表示泛型的通配符(?)类型,比如List<?>中的?。它的定义如下:

    public interface WildcardType extends Type {
        Type[] getUpperBounds();
        Type[] getLowerBounds();
    }
    

    WildcardType接口提供了两个接口,分别获取通配符?的上下边界。比如List<? extends Person>的上边界是Person ClassList<? super Person>的下边界是Person Class

    2 获取Type接口信息

    我们可以通过类的全限定域名或类的对象获取Class对象,Type则可以通过ClassFieldMethodConstructorParameter这些表示类的元数据对象获取,因为FieldMethodConstructorParameter只能通过Class间接获取,所以Type信息都是从Class获取的。

    上述对象获取Class信息的接口,接口名前带有generic前缀的往往就是获取相应Type信息的接口

    下面通过一些实例观察获取Type的一些接口信息,递归打印Type信息的方法:

        public static void printTypeInfo(final Type type) {
    
            log.info("type.getTypeName(): {}", type.getTypeName());
            if (type instanceof Class) {
                Class c = (Class) type;
                log.info("type is Class");
            } else if (type instanceof ParameterizedType) {
                ParameterizedType t = (ParameterizedType) type;
                log.info("type is ParameterizedType");
    
                Type[] actualTypeArguments = t.getActualTypeArguments();
                log.info("ParameterizedType.getActualTypeArguments(): {}", Arrays.toString(actualTypeArguments));
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    printTypeInfo(actualTypeArguments[i]);
                }
    
                Type rawType = t.getRawType();
                log.info("ParameterizedType.getRawType(): {}", rawType);
                printTypeInfo(rawType);
    
                Type ownerType = t.getOwnerType();
                log.info("ParameterizedType.getOwnerType(): {}", ownerType);
                if (ownerType != null) {
                    printTypeInfo(ownerType);
                }
    
            } else if (type instanceof TypeVariable) {
                TypeVariable t = (TypeVariable) type;
                log.info("type is TypeVariable");
    
                String name = t.getName();
                log.info("TypeVariable.getName(): {}", name);
    
                Type[] bounds = t.getBounds();
                log.info("TypeVariable.getBounds(): {}", Arrays.toString(bounds));
                if (bounds != null) {
                    for (int i = 0; i < bounds.length; i++) {
                        printTypeInfo(bounds[i]);
                    }
                }
    
            } else if (type instanceof GenericArrayType) {
                GenericArrayType t = (GenericArrayType) type;
                log.info("type is GenericArrayType");
                Type componentType = t.getGenericComponentType();
                log.info("GenericArrayType.getGenericComponentType(): {}", componentType);
                printTypeInfo(componentType);
            } else if (type instanceof WildcardType) {
                WildcardType t = (WildcardType) type;
                log.info("type is WildcardType");
    
                Type[] upperBounds = t.getUpperBounds();
                log.info("WildcardType.getUpperBounds(): {}", Arrays.toString(upperBounds));
                if (upperBounds != null) {
                    for (int i = 0; i < upperBounds.length; i++) {
                        printTypeInfo(upperBounds[i]);
                    }
                }
    
                Type[] lowerBounds = t.getLowerBounds();
                log.info("WildcardType.getLowerBounds(): {}", Arrays.toString(lowerBounds));
                if (lowerBounds != null) {
                    for (int i = 0; i < lowerBounds.length; i++) {
                        printTypeInfo(lowerBounds[i]);
                    }
                }
            }
    
        }
    

    2.1 Class

    用来测试的类:

    public interface Interface1 {
    }
    
    public interface Interface2<T1, T2> {
    }
    
    public class Class2<T> {
    }
    
    public class Class1<T, S> extends Class2<S> implements Interface1, Interface2<String, T> {
    }
    
    

    2.1.1 获取父类的Type: getGenericSuperclass()

    测试代码:

        Class c = Class1.class;
    
        Type genericSuperclass = c.getGenericSuperclass();
        log.info("=====begin print genericSuperclass");
        if (genericSuperclass != null) {
            printTypeInfo(genericSuperclass);
        }
        log.info("=====finish print genericSuperclass");
    

    打印结果:

    =====begin print genericSuperclass
    type.getTypeName(): com.javatest.generic.Class2<S>
    type is ParameterizedType
    ParameterizedType.getActualTypeArguments(): [S]
    type.getTypeName(): S
    type is TypeVariable
    TypeVariable.getName(): S
    TypeVariable.getBounds(): [class java.lang.Object]
    type.getTypeName(): java.lang.Object
    type is Class
    ParameterizedType.getRawType(): class com.javatest.generic.Class2
    type.getTypeName(): com.javatest.generic.Class2
    type is Class
    ParameterizedType.getOwnerType(): null
    =====finish print genericSuperclass
    

    2.1.2 获取父接口的Type: getGenericInterfaces()

    测试代码:

        Type[] genericSuperInterfaces = c.getGenericInterfaces();
        log.info("=====begin print genericSuperInterfaces");
        if (genericSuperInterfaces != null) {
    
            for (int i = 0; i < genericSuperInterfaces.length; i++) {
                log.info("=====begin print genericSuperInterfaces, i={}", i);
                printTypeInfo(genericSuperInterfaces[i]);
                log.info("=====finish print genericSuperInterfaces i={}", i);
            }
        }
        log.info("=====finish print genericSuperInterfaces");
    

    打印结果:

    =====begin print genericSuperInterfaces
    =====begin print genericSuperInterfaces, i=0
    type.getTypeName(): com.javatest.generic.Interface1
    type is Class
    =====finish print genericSuperInterfaces i=0
    =====begin print genericSuperInterfaces, i=1
    type.getTypeName(): com.javatest.generic.Interface2<java.lang.String, T>
    type is ParameterizedType
    ParameterizedType.getActualTypeArguments(): [class java.lang.String, T]
    type.getTypeName(): java.lang.String
    type is Class
    type.getTypeName(): T
    type is TypeVariable
    TypeVariable.getName(): T
    TypeVariable.getBounds(): [class java.lang.Object]
    type.getTypeName(): java.lang.Object
    type is Class
    ParameterizedType.getRawType(): interface com.javatest.generic.Interface2
    type.getTypeName(): com.javatest.generic.Interface2
    type is Class
    ParameterizedType.getOwnerType(): null
    =====finish print genericSuperInterfaces i=1
    =====finish print genericSuperInterfaces
    

    2.1.3 获取类型参数的Type: getTypeParameters()

    测试代码:

        TypeVariable[] typeVariables = c.getTypeParameters();
        log.info("=====begin print typeVariables");
        if (typeVariables != null) {
    
            for (int i = 0; i < typeVariables.length; i++) {
                log.info("=====begin print typeVariables, i={}", i);
                printTypeInfo(typeVariables[i]);
                log.info("=====finish print typeVariables i={}", i);
            }
        }
        log.info("=====finish print typeVariables");
    

    打印结果:

    =====begin print typeVariables
    =====begin print typeVariables, i=0
    type.getTypeName(): T
    type is TypeVariable
    TypeVariable.getName(): T
    TypeVariable.getBounds(): [class java.lang.Object]
    type.getTypeName(): java.lang.Object
    type is Class
    =====finish print typeVariables i=0
    =====begin print typeVariables, i=1
    type.getTypeName(): S
    type is TypeVariable
    TypeVariable.getName(): S
    TypeVariable.getBounds(): [class java.lang.Object]
    type.getTypeName(): java.lang.Object
    type is Class
    =====finish print typeVariables i=1
    =====finish print typeVariables
    

    2.2 Field

    用来测试的类

    public class Class2<T> {
        
        String str;
        List<String> strList1;
        List<T> strList2;
        T t1;
        
    }
    

    2.2.1 类属性的Type: getGenericType()

    测试代码:

        Class c = Class2.class;
    
        log.info("=====begin pring field str");
        Field f = c.getDeclaredField("str");
        Type type = f.getGenericType();
        printTypeInfo(type);
        log.info("=====finish pring field str");
    
        log.info("=====begin pring field strList1");
        f = c.getDeclaredField("strList1");
        type = f.getGenericType();
        printTypeInfo(type);
        log.info("=====finish pring field strList1");
    
        log.info("=====begin pring field strList2");
        f = c.getDeclaredField("strList2");
        type = f.getGenericType();
        printTypeInfo(type);
        log.info("=====finish pring field strList2");
    
        log.info("=====begin pring field t1");
        f = c.getDeclaredField("t1");
        type = f.getGenericType();
        printTypeInfo(type);
        log.info("=====finish pring field t1");
    

    打印结果:

    =====begin pring field str
    type.getTypeName(): java.lang.String
    type is Class
    =====finish pring field str
    =====begin pring field strList1
    type.getTypeName(): java.util.List<java.lang.String>
    type is ParameterizedType
    ParameterizedType.getActualTypeArguments(): [class java.lang.String]
    type.getTypeName(): java.lang.String
    type is Class
    ParameterizedType.getRawType(): interface java.util.List
    type.getTypeName(): java.util.List
    type is Class
    ParameterizedType.getOwnerType(): null
    =====finish pring field strList1
    =====begin pring field strList2
    type.getTypeName(): java.util.List<T>
    type is ParameterizedType
    ParameterizedType.getActualTypeArguments(): [T]
    type.getTypeName(): T
    type is TypeVariable
    TypeVariable.getName(): T
    TypeVariable.getBounds(): [class java.lang.Object]
    type.getTypeName(): java.lang.Object
    type is Class
    ParameterizedType.getRawType(): interface java.util.List
    type.getTypeName(): java.util.List
    type is Class
    ParameterizedType.getOwnerType(): null
    =====finish pring field strList2
    =====begin pring field t1
    type.getTypeName(): T
    type is TypeVariable
    TypeVariable.getName(): T
    TypeVariable.getBounds(): [class java.lang.Object]
    type.getTypeName(): java.lang.Object
    type is Class
    =====finish pring field t1
    
    

    2.3 Method

    从上面ClassField的例子应该知道怎么回事了,后面不再给出例子,只给出获取Type信息的方法

    2.3.1 方法参数的Type: getGenericParameterTypes()

    2.3.2 方法返回值的Type: getGenericReturnType()

    2.3.3 方法声明的抛出异常的Type: getGenericExceptionTypes()

    2.4 Constructor

    2.3.1 构造器参数的Type: getGenericParameterTypes()

    2.3.2 构造器声明的抛出异常的Type: getGenericExceptionTypes()

    2.5 Parameter

    2.5.1 参数的Type: getParameterizedType()

    相关文章

      网友评论

          本文标题:Java Type类型

          本文链接:https://www.haomeiwen.com/subject/dienzctx.html