欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java反射获取泛型相关信息

程序员文章站 2024-03-14 18:36:41
...

GenericArrayType

泛型数组,组成数组的元素中有范型则实现了该接口; 它的组成元素是ParameterizedType或TypeVariable类型,它只有一个方法:
Type getGenericComponentType(): 返回数组的组成对象

package com.enjoy.reflect.genericArrayType;

import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;


public class GenericArrayTypeTest<T> {
    List<String>[] lists;

    public static void main(String[] args) {
        //尝试获取数组lists的填充数据类型
        Class clz = GenericArrayTypeTest.class;
        try {
            Field field = clz.getDeclaredField("lists");
            //获取填充数组的数据类型
            GenericArrayType type = (GenericArrayType) field.getGenericType();
            Type arraytype = type.getGenericComponentType();//泛型数组的声明类型,包含泛型信息
            System.out.println("====================="+arraytype);
            //获取填充数组的数据类型,如果数据类型是泛型,那么获取的是承载泛型的对象的数据类型
            ParameterizedType parameterizedType = (ParameterizedType) arraytype;
            //parameterizedType.getRawType(),获取承载泛型的类信息
            System.out.println("=============="+parameterizedType.getRawType());
            //获取泛型的实际类型
            for (Type actualTypeArgument : parameterizedType.getActualTypeArguments()) {
                System.out.println("===========actualTypeArgument = "+actualTypeArgument);
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

Java反射获取泛型相关信息

ParameterizedType

ParameterizedType
具体的泛型类型, 如Map<String, String>
有如下方法:

Type getRawType(): 返回承载该泛型信息的对象, 如上面那个Map<String, String>承载范型信息的对象是Map
Type[] getActualTypeArguments(): 返回实际泛型类型列表, 如上面那个Map<String, String>实际范型列表中有两个元素, 都是String

package com.enjoy.reflect.parameterizedType;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

public class ParameterizedTypeTest {
    Map<String,Integer> map;

    public static void main(String[] args) throws Exception {
        Field field = ParameterizedTypeTest.class.getDeclaredField("map");
        System.out.println("==========GenericType = "+field.getGenericType());
        ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
        Type rawType = parameterizedType.getRawType();
        System.out.println("========rawType = "+rawType);
        //Map中泛型是2个,实际应用中,可能会有多个,所以是数组
        Type[] typeArguments = parameterizedType.getActualTypeArguments();
        for (Type typeArgument : typeArguments) {
            System.out.println("=========== typeArgument = "+typeArgument);
            System.out.println("=========== typeArgument.getTypeName = "+typeArgument.getTypeName());
        }
    }
}

运行结果:

Java反射获取泛型相关信息

TypeVariable

TypeVariable
泛型变量, 泛型信息在编译时会被转换为一个特定的类型, 而TypeVariable就是用来反映在JVM编译该泛型前的信息.
TypeVariable就是<T>、<C extends Collection>中的变量T、C本身; 它有如下方法:
Type[] getBounds(): 获取类型变量的上边界, 若未明确声明上边界则默认为Object
getGenericDeclaration(): 获取声明该类型变量的类型
String getName(): 获取在源码中定义时的名字
注意:
类型变量在定义的时候只能使用extends进行(多)边界限定, 不能用super;
为什么边界是一个数组? 因为类型变量可以通过&进行多个上边界限定,因此上边界有多个

 

package com.enjoy.reflect.typeVariable;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class TypeVariableTest<K extends Comparable & Serializable,V> {
    K key;
    V value;

    public static void main(String[] args) throws Exception {
        Field fk = TypeVariableTest.class.getDeclaredField("key");
        Field fv = TypeVariableTest.class.getDeclaredField("value");

        TypeVariable typeVariableK = (TypeVariable) fk.getGenericType();
        TypeVariable typeVariableV = (TypeVariable) fv.getGenericType();
        System.out.println("========== typeVariableK.name = "+typeVariableK.getName());
        System.out.println("========== typeVariableV.name = "+typeVariableV.getName());

        GenericDeclaration kDecla = typeVariableK.getGenericDeclaration();
        GenericDeclaration vDecla = typeVariableV.getGenericDeclaration();
        System.out.println("============ kDecla = "+kDecla);
        System.out.println("============ VDecla = "+vDecla);

        Type[] kbounds = typeVariableK.getBounds();
        for (Type kbound : kbounds) {
            System.out.println("========== kbound = "+kbound);
        }

        Type[] vbounds = typeVariableV.getBounds();
        for (Type vbound : vbounds) {
            System.out.println("========== vbound = "+vbound);
        }
    }
}

运行结果:

Java反射获取泛型相关信息

WildcardType

WildcardType

该接口表示通配符泛型, 比如? extends Number 和 ? super Integer 它有如下方法:

Type[] getUpperBounds(): 获取范型变量的上界

Type[] getLowerBounds(): 获取范型变量的下界

注意:现阶段通配符只接受一个上边界或下边界, 返回数组是为了以后的扩展, 实际上现在返回的数组的大小是1

package com.enjoy.reflect.wildcardType;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.WildcardType;
import java.util.List;

public class WildcardTypeTest {
    private List<? extends Number> numbers;
    private List<? super String> s;

    public static void main(String[] args) throws Exception {
        Field nf = WildcardTypeTest.class.getDeclaredField("numbers");
        Field af = WildcardTypeTest.class.getDeclaredField("s");

        //获取泛型参数类型
        ParameterizedType nftype = (ParameterizedType) nf.getGenericType();
        ParameterizedType aftype = (ParameterizedType) af.getGenericType();
        //获取泛型通配符类型
        WildcardType nfwType = (WildcardType) nftype.getActualTypeArguments()[0];
        WildcardType afwType = (WildcardType) aftype.getActualTypeArguments()[0];

        System.out.println("=============nfwType up"+nfwType.getUpperBounds()[0]);
//        System.out.println("=============nfwType lower"+nfwType.getLowerBounds()[0]);//运行报错,extends限定的是上界,没有下界

//        System.out.println("=============afwType up"+afwType.getUpperBounds()[0]);//运行报错,super限定的是下界,没有上界

        System.out.println("=============afwType lower"+afwType.getLowerBounds()[0]);

    }
}

运行结果:

Java反射获取泛型相关信息

以上几个类型都是继承是Type类的,java.lang.reflect.Type。

如果需要在反射的时候获取泛型相关的信息,就可以使用上述几个类达到目的。

举个例子:解析Gson数据为相应的Bean类。

首先有个TypeReference类,定义如下:

package com.enjoy.reflect.gson.type;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class TypeReference<T> {
    Type type;
    T t;

    protected TypeReference(){
        //注意.class和getClass的区别
        /*两者的区别如下:
        类名.class叫做“类字面量”,因class是关键字, 所以类名.class编译时确定。而getclass()是某个具体的方法来调用,是运行时根据实际实例确定,getClass()是动态而且是final的。

        例如:
        String.class 是能对类名的引用取得在内存中该类型class对象的引用,而new String().getClass() 是通过实例对象取得在内存中该实际类型class对象的引用。
        */

        //这里注意getSuperclass和getGenericSuperclass的区别,
        // getGenericSuperclass包含泛型信息,getSuperclass不包含泛型信息
        Type genericSuperClz = getClass().getGenericSuperclass();
        System.out.println("======= TypeReference genericSuperClz = "+genericSuperClz
                +"\n=========type = "+getType()+"\n======.class = "+TypeReference.class);
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperClz;
        //因为类泛型可以定义多个  A<T,E..> 所以是个数组
        Type[] types = parameterizedType.getActualTypeArguments();
        type = types[0];
    }

    public Type getType(){
        return type;
    }

}

然后有一个DeSerialized类,定义如下:

package com.enjoy.reflect.gson;

import com.enjoy.reflect.gson.type.TypeReference;
import com.google.gson.Gson;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class DeSerialized {

    static class Response<T> {
        T data;
        int code;
        String message;

        @Override
        public String toString() {
            return "Response{" +
                    "data=" + data +
                    ", code=" + code +
                    ", message='" + message + '\'' +
                    '}';
        }

        public Response(T data, int code, String message) {

            this.data = data;
            this.code = code;
            this.message = message;
        }

        /*public Type getType(){
            Type type = null;
            Type tempType = getClass().getGenericSuperclass();
            System.out.println("==========tempType = "+tempType);
            ParameterizedType parameterizedType = (ParameterizedType) tempType;
            type = parameterizedType.getActualTypeArguments()[0];
            System.out.println("==============response getType = "+type);
            return type;
        }*/
    }


    static class Data {
        String result;

        public Data(String result) {
            this.result = result;
        }

        @Override
        public String toString() {
            return "Data{" +
                    "result=" + result +
                    '}';
        }
    }


    public static void main(String[] args) {
        Response<Data> response = new Response<>(new Data("Rayman"),888,"Yes");
//        response.getType();

        Gson gson = new Gson();
        String json = gson.toJson(response);
        System.out.println("========json = "+json);

        //反序列化......

        /**
         *  有花括号: 代表是匿名内部类,创建一个匿名内部类的实例对象
         *  没花括号:创建实例对象
         *  如果创建的是实例对象,比如:Type type = new TypeReference<Response<Data>>().getType();
            那么getClass().getGenericSuperclass()获取的Type是Object, 并不包含泛型信息;
         *  必须是内部类匿名类,通过getClass().getGenericSuperclass()获取的Type才包含泛型信息
         */
        Type type = new TypeReference<Response<Data>>(){}.getType();
        System.out.println("=========type = "+type);

        Response<Data> ret = gson.fromJson(json,type);
        System.out.println("============ret = "+ret);
    }
}

运行结果:

========json = {"data":{"result":"Rayman"},"code":888,"message":"Yes"}
======= TypeReference genericSuperClz = com.enjoy.reflect.gson.type.TypeReference<com.enjoy.reflect.gson.DeSerialized$Response<com.enjoy.reflect.gson.DeSerialized$Data>>
=========type = null
======.class = class com.enjoy.reflect.gson.type.TypeReference
=========type = com.enjoy.reflect.gson.DeSerialized$Response<com.enjoy.reflect.gson.DeSerialized$Data>
============ret = Response{data=Data{result=Rayman}, code=888, message='Yes'}

可以看到,这里借助辅助类TypeReference<T>成功的解析出来Gson中含有的泛型Bean类。