如何获取泛型T的真实类型

一.Type类是啥

Type是Java 编程语言中所有类型的公共高级接口(官方解释),也就是Java中所有类型的"爹",它并不是我们平常工作中经常使用的 int、String、List、Map等数据类型,而是从Java语言角度来说,对基本类型、引用类型向上的抽象;

Type体系中类型的包括:

  • 原始类型(Type):不仅仅包含我们平常所指的类,还包括枚举、数组、注解等
  • 参数化类型(ParameterizedType):就是我们平常所用到的泛型List<String>、Map<K,V>,Set<T>,Class<?>
  • 数组类型(GenericArrayType):并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[]
  • 类型变量(TypeVariable):比如 T a
  • 基本类型(Class):原始类型,每个类(貌似接口也有)都会有个Class对象

我们重点看一下ParameterizedType :

java 复制代码
public interface ParameterizedType extends Type {
    // 获取<>中实际的类型参数,以Type数组形式返回
    Type[] getActualTypeArguments();
    // 获取<>前面的类型
    Type getRawType();
    // 如果这个类型是某个类型所属,则获取这个所有者的类型,否则返回null,比如Map.Entry<Sting,String>,会返回Map
    Type getOwnerType();
}

具体可参考:https://www.jianshu.com/p/0f3eda48d611

二.如何获得泛型T的真实类型

反射拿到泛型接口的实现类的实际泛型类型

定义一个泛型接口和他的实现类:

java 复制代码
public interface IMessageSender<T,K> {
    K sendMsg(T msg);
}

public class SmsMessageImpl implements IMessageSender<String, List<Integer>>, Serializable{
    @Override
    public List<Integer> sendMsg(String msg) {
        return new ArrayList<>();
    }
}

通过反射拿到SmsMessageImpl实现的接口里面的T,K的真实类型:

java 复制代码
    /**
     * 反射拿到泛型接口的实现类的实际泛型类型
     */
    public static void testClassGenericActualType1(){
        System.out.println("testClassGenericActualType1开始");
        //getGenericInterfaces返回表示由此对象表示的类或接口直接实现的接口的Type
        //IMessageSender<String, List<Integer>>
        Type genericInterfaces1 = SmsMessageImpl.class.getGenericInterfaces()[0];
        //Serializable
        Type genericInterfaces2 = SmsMessageImpl.class.getGenericInterfaces()[1];

        //输出的是sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
        System.out.println(genericInterfaces1.getClass());
        //输出的是class java.lang.Class
        System.out.println(genericInterfaces2.getClass());

        //返回表示此类型实际类型参数的 Type对象的数组
        Type[] actualTypeArguments = ((ParameterizedType)genericInterfaces1).getActualTypeArguments();
        //class java.lang.String , java.util.List<java.lang.Integer>
        //这边直接拿到了SmsMessageImpl中两个实际泛型类型
        System.out.println("反射拿到泛型接口的实现类的实际泛型类型:"+actualTypeArguments[0] + " , "+ actualTypeArguments[1]);
        System.out.println("testClassGenericActualType1结束");
    }

输出结果是:

java 复制代码
testClassGenericActualType1开始
class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
class java.lang.Class
反射拿到泛型接口的实现类的实际泛型类型:class java.lang.String , java.util.List<java.lang.Integer>
testClassGenericActualType1结束

反射拿到父类的实际泛型类型

定义一个泛型类,和他的子类:

java 复制代码
public class MessageSender <T>{

}

public class SmsMessage extends MessageSender<String>{
}

通过对SmsMessage的class对象进行反射拿到父类里面真实的String类型:

java 复制代码
public static void testClassGenericActualType2(){
        System.out.println("testClassGenericActualType2开始");
        //返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的Type。如果超类是 
        //参数化类型,则返回的 Type 对象必须准确反映源代码中所使用的实际类型参数
        Type genericSuperclass = SmsMessage.class.getGenericSuperclass();
        Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
        System.out.println("反射拿到父类的实际泛型类型:"+actualTypeArguments[0]);
        System.out.println("testClassGenericActualType2结束");

    }

输出结果是:

java 复制代码
testClassGenericActualType2开始
反射拿到父类的实际泛型类型:class java.lang.String
testClassGenericActualType2结束

反射获取方法参数上泛型参数的实际类型

我们定义了一个verify方法:

java 复制代码
public class Main {

    public static void main(String[] args) throws NoSuchMethodException{
        testMethodGenericActualType();
    }

    /**
     * 获取方法参数上泛型参数的实际类型
     * @throws NoSuchMethodException
     */
    public static void testMethodGenericActualType() throws NoSuchMethodException {
        System.out.println("testMethodGenericActualType开始");
        //反射拿到Main.class中的verify方法
        Method method = Main.class.getMethod("verify", Map.class);
        //反射拿到verify方法的参数列表的第一个参数
        Parameter parameter = method.getParameters()[0];
        Type type = parameter.getParameterizedType();
        //由于参数是带泛型的,因此type的实际类型是ParameterizedType,
        //可以强制转换为ParameterizedType,然后获取参数Map中的两个泛型参数: <String,Integer>
        Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
        System.out.println("获取方法参数上泛型参数的实际类型:"+actualTypeArguments[0] + " , " + actualTypeArguments[1]);
        System.out.println("testMethodGenericActualType结束");

    }

    /**
     * 用于测试获取方法参数上泛型参数的实际类型
     * @param map
     */
    public void verify(Map<String,Integer> map){
    }



}

输出结果是:

java 复制代码
testMethodGenericActualType开始
获取方法参数上泛型参数的实际类型:class java.lang.String , class java.lang.Integer
testMethodGenericActualType结束

反射获取字段上泛型参数的实际类型

java 复制代码
public class Main {

    public static void main(String[] args) throws NoSuchFieldException {

        testFieldGenericActualType();
    }


    /**
     * 获取字段上泛型参数的实际类型
     */
    public static void testFieldGenericActualType() throws NoSuchFieldException {
        System.out.println("testFieldGenericActualType开始");
        Field field = Main.class.getDeclaredField("list");
        //获取字段泛型
        ParameterizedType genericType = (ParameterizedType) field.getGenericType();
        Type[] actualTypeArguments = genericType.getActualTypeArguments();
        //得到字段List<String>泛型中的实际类型String
        System.out.println("获取字段上泛型参数的实际类型:"+actualTypeArguments[0]);
        System.out.println("testFieldGenericActualType结束");
    }

    private List<String> list;


}

输出结果是:

java 复制代码
testFieldGenericActualType开始
获取字段上泛型参数的实际类型:class java.lang.String
testFieldGenericActualType结束
相关推荐
Am心若依旧40912 分钟前
[c++11(二)]Lambda表达式和Function包装器及bind函数
开发语言·c++
明月看潮生14 分钟前
青少年编程与数学 02-004 Go语言Web编程 20课题、单元测试
开发语言·青少年编程·单元测试·编程与数学·goweb
大G哥24 分钟前
java提高正则处理效率
java·开发语言
指尖上跳动的旋律27 分钟前
shell脚本定义特殊字符导致执行mysql文件错误的问题
数据库·mysql
ROBOT玲玉28 分钟前
Milvus 中,FieldSchema 的 dim 参数和索引参数中的 “nlist“ 的区别
python·机器学习·numpy
VBA633734 分钟前
VBA技术资料MF243:利用第三方软件复制PDF数据到EXCEL
开发语言
轩辰~36 分钟前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议
一勺菠萝丶38 分钟前
MongoDB 常用操作指南(Docker 环境下)
数据库·mongodb·docker
小_太_阳1 小时前
Scala_【1】概述
开发语言·后端·scala·intellij-idea
向宇it1 小时前
【从零开始入门unity游戏开发之——unity篇02】unity6基础入门——软件下载安装、Unity Hub配置、安装unity编辑器、许可证管理
开发语言·unity·c#·编辑器·游戏引擎