Gson源码阅读--之Java反射Type类型知识

一、背景

在阅读Gson源码前需要掌握有关Java的Type类型的知识点。

二、Type类型

2.1 Java编程语言中的所有类型

Type是Java编程语言中所有类型的父接口。这里的所有的Java类型包括原生类型(raw types),参数化类型(Parameterized Types)、数组类型(GenericArray Type)、类型变量(Type Variables)和基本类型(primitive types)。
原生类型(raw types):指一般类型,如String,Number,另外还包括枚举、数组和注解等。
参数化类型(Parameterized types):表示一种参数化的类型,比如Collection,即普通的泛型。可参考List、Map。
数组类型(GenericArray Type):表示泛型定义的数组,这里的数组内中的item可以是参数化类型(parameterized types)或类型变量(type variables),但是并不是原生类型和基本类型。
类型变量(Type variables):表示类型变量,并不确定其类型,比如:V,
基本类型(primitive types): int、float、double等。
Type类型的由来
Type是在JDK1.5开始引入,引入的主要原因是因为泛型,在JDK1.5之前的版本中没有泛型只有原生类型。所有的原生类型都是通过字节码文件类Class进行抽象。Class类的一个具体对象就代表一个指定的原生对象。
在泛型出现之后,扩充了数据类型。也就是从原生类型扩充了参数化类型、类型变量类型和泛型数组类型,它们三属于Type的子接口。
此处存在一个问题,为什么这些类型没有统一到Class下,而是新增加一个Type?
一切都是为了程序的扩展性,于是最后引入了Type接口作为Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType这几种类型的总的父接口。

2.2 Type类型的子孙
Type类型UML图如下
这里写图片描述
Type直接子类
Type的直接子类只有一个,即Class,代表着Type类型中原始类型和基本类型。此处Class是Type的一种实现,是对Java类的抽象,描述的是类的信息,包括类的修饰符(public/private/protect/default/static/final等)、类的类型(一般类、枚举、注释、接口、数组等)、类的构造器、类的字段、类的方法等信息。
Class同样也是反射机制的基础,反射API通过操作Class可以获取Java程序运行期间,每个对象所属的类详细信息。虚拟机为每个类型管理一个Class对象,因此可以用==运算符实现两个类对象比较的操作。
获取class的常用方式:
1.调用getClass() Object类中的getClass()方法返回一个Class类型的实例

Boolean var1 = true;
Class<?> classType2 = var1.getClass();
System.out.println(classType2); //输出:class java.lang.Boolean

2.运用T.class 语法(T是任意的Java类型)

Class<?> classType4 = Boolean.class;
System.out.println(classType4);//输出:class java.lang.Boolean 

3.运用static method Class.forName()(使用时应该提供异常处理器)

Class<?> classType5 = Class.forName("java.lang.Boolean");System.out.println(classType5);//输出:class java.lang.Boolean 

4.运用primitive wrapper classes的TYPE 语法(这里返回的是原生类型,和Boolean.class返回的不同)

Class<?> classType3 = Boolean.TYPE;
System.out.println(classType3);//输出:boolean 

Class常用的方法:

方法 说明 例子
getName() 返回类的名字 String.class.getName(); //返回”java.lang.String”
newInstance() 快速地创建一个类的实例(调用默认构造器,如果该类没有默认构造器,抛出异常)(如果要为构造器提供参数,使java.lang.reflect.Constructor中的newInstance方法) String s = “java.util.Date”;Object m = Class.forName(s).newInstance();
getSuperclass() 返回超类
getFields() getMethods() getConstructors()(还有带字符串参数,给定名称的形式) 分别返回类支持的public域、方法和构造器数组,其中包括超类的公有成员
getDeclaredFields() getDeclaredMethods() getDeclaredConstructors()(还有给定名称的形式) 分别返回类中声明的全部域、方法和构造器数组。其中包括私有和保护成员,但不包括超类的成员

Type子接口
1. ParameterizedType
参数化类型,即泛型,官方解释是“ParameterizedType represents a parameterized type such as
Collection< String>”,需要注意的是,官方只是给了一个泛型的参照。Parameterized类型可以参考如下示例:

//ParameterizedType类型
    Map<String, Person> map;
    Set<String> set1;
    Class<?> clz;
    Holder<String> holder;
    List<String> list;

    static class Holder<V>{

    }
//非ParameterizedType类型
Set set;
List aList;

ParameterizedType的主要方法
getActualTypeArguments
获取参数化类型<>中的类型参数的类型,因为可能有多个类型参数,例如Map< K, V>,所以返回的是一个Type[]数组。另外需要注意的地方是无论<>中存在几层<>嵌套,这个方法仅仅脱去最外层的<>,之后剩下的内容就作为这个方法的返回值,所以其返回值类型不一定。参考如下示例:

1. List<ArrayList> a1;//这里返回的是ArrayList,Class类型 
2. List<ArrayList<String>> a2;//这里返回的是ArrayList<String>,ParameterizedType类型
3. List<T> a3;//返回的是T,TypeVariable类型 
4. List<? extends Number> a4; //返回的是WildcardType类型 
5. List<ArrayList<String>[]> a5;//返回的是GenericArrayType 

getRawType
返回最外层<>前面那个类型,比如Map< K, V>返回Map。

getOwnerType
获得这个类型的所有者的类型,这一点可以参考在一个类或接口其内部定义接口或者类,外部类或接口的类型就是内部接口和类的所有者类型。比如参考如下:

//Map的源码
public interface Map<K, V> {
...
interface Entry<K, V> {
...
}
...
}
//Map.Entry的接口所有者就是Map

2.TypeVariable
类型变量,描述类型也就是泛型中的变量,表示泛指任意或相关一类类型,也就是说狭义上的泛型(泛指某一类类型),一般用大写字母作为变量,比如K、V、E等。
TypeVariable的源码如下:

public interface TypeVariable<D extends GenericDeclaration> extends Type {
   //获得泛型的上限,若未明确声明上边界则默认为Object
    Type[] getBounds();
    //获取声明该类型变量实体(即获得类、方法或构造器名)
    D getGenericDeclaration();
    //获得名称,即K、V、E之类名称
    String getName();
}

类型变量的定义,< E>,在E的前后加上尖括号,参考如下:

//1.在类class上定义类型变量
class A<T> {
    T a;
}

//2.在方法上定义,方法上类型变量定义不是在参数里边,必须在返回值之前,static等修饰符后
public <E> void test(E e) {}

//3.定义在构造器上
public <K> A(K k) {} 

注意:类型变量定义的时候不能定义下限(即不能有super),否则编译报错。T extends classA表示泛型有上限class A,因为在使用过程中能够保证传入的参数拥有class A的方法和属性,但是T super class A就不能确定传入的参数和方法了。
类型变量所具有的方法
getBounds
获得该类型变量的上限,也就是泛型中extend右边的值,例如List< T extends Number>,Number就是类型变量T的上限;如果只是简单的定义了List< T>,没有显示的定义extends,则默认的上限是Object。参考如下范例:

//没有定义extends的情况下
public class TypeVariableTest<T> {

    private T list = null;

    public static void main(String[] args) {

        try {
            Field field = TypeVariableTest.class.getDeclaredField("list");

            Type type = field.getGenericType();
            if (type instanceof TypeVariable) {
                TypeVariable tv = (TypeVariable) type;
                Type[] types = tv.getBounds();
                for (Type t : types) {
                    System.out.println(t);//结果输出 class java.lang.Object
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

//在显示定义extends的情况下
public class ParameterizedTest<T extends Number & Serializable & Comparable> {

    private T t;

    public static void main(String[] args) {

        try {
            Field field = ParameterizedTest.class.getDeclaredField("t");

            Type type = field.getGenericType();

            if (type instanceof TypeVariable) {
                TypeVariable tType = (TypeVariable) type;

                Type[] types = tType.getBounds();

                for (Type t : types) {
                    System.out.println(t);//结果输出class java.lang.Number interface java.io.Serializable interface java.lang.Comparable
                }
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

getGenericDeclaration
获取声明该类型变量实体(Class,Constructor,Method)

public class ParameterizedTest<T> {

    private T t;

    public static void main(String[] args) {

        try {
            Field field = ParameterizedTest.class.getDeclaredField("t");

            Type type = field.getGenericType();

            if (type instanceof TypeVariable) {
                TypeVariable tType = (TypeVariable) type;

                GenericDeclaration genericDeclaration = tType.getGenericDeclaration();
                System.out.println(genericDeclaration);//结果输出 class com.king.testreflect.ParameterizedTest
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

getName
获取类型变量在源码中定义的名称。

public class ParameterizedTest<T> {

    private T t;

    public static void main(String[] args) {

        try {
            Field field = ParameterizedTest.class.getDeclaredField("t");

            Type type = field.getGenericType();

            if (type instanceof TypeVariable) {
                TypeVariable tType = (TypeVariable) type;

                String name = tType.getName();
                System.out.println(name);//结果输出 T
            }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

3.GenericArrayType
泛型数组类型,表示上面两种类型的数组,描述的形式如:A< T>[]或T[]。
源码如下:

public interface GenericArrayType extends Type {
    //获得这个数组元素类型,即获得:A<T>(A<T>[])或T(T[])
    Type getGenericComponentType();
}

方法注意:无论从左向右存在几个[]并列,这个方法仅仅会脱去最右边[]之后剩下的内容充当这个方法的返回值。参考如下:

classA<K>[][] key;
Type type = Main.class.getDeclaredField("key").getGenericType();  System.out.println(((GenericArrayType)type).getGenericComponentType());
//输出结果
//com.fcc.test.classA<K>[]

4.WildcardType
通配符表达式,或泛型表达式,他虽然是Type的一个子接口,但并不是Java类型中的一种,表示的仅仅形如 ? extends T,? super K这样的通配符表达式。源码参考如下:

public interface WildcardType extends Type {
    //获得泛型表达式上界(上限)
    Type[] getUpperBounds();
    //获得泛型表达式下界(下限)
    Type[] getLowerBounds();
}

getUpperBounds
获取泛型表达式上届,根据API的注释提示:现阶段通配符表达式仅仅接受一个上边界或者下边界,这个和定义类型变量时候可以指定多个上边界是不一样。但是API为了保持扩展性,这里返回值为数组形式。
getLowerBounds
获取泛型表达式下界。
参考代码如下:

public <T> void test(List<? extends classA > a){}
Method method = Main.class.getMethod("test",List.class);
        Type[] upperBounds = null;
        Type[] lowerBounds = null;
        Type[] types = method.getGenericParameterTypes();
        for(Type type : types){
        Type[] actualTypeArgument = ((ParameterizedType)type).getActualTypeArguments();
            for(Type t : actualTypeArgument){
                WildcardType wildcardType = (WildcardType) t;
                lowerBounds = wildcardType.getLowerBounds();
                upperBounds = wildcardType.getUpperBounds();
                System.out.println("通配符表达式类型是:"+ wildcardType);
                if(upperBounds.length != 0){
                    System.out.println("表达式上边界:"+Arrays.asList(upperBounds));
                    }
                if(lowerBounds.length != 0){
                    System.out.println("表达式下边界:"+Arrays.asList(lowerBounds));
                    }
            }
        }
//输出结果
通配符表达式类型是:? extends com.fcc.test.classA
表达式上边界:[class com.fcc.test.classA]

参考博客

https://blog.csdn.net/kingdam578/article/details/78656626
https://blog.csdn.net/gdutxiaoxu/article/details/68926515
https://blog.csdn.net/a327369238/article/details/52621043

猜你喜欢

转载自blog.csdn.net/polo2044/article/details/80890402
今日推荐