如何获取泛型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 :

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的真实类型

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

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

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的真实类型:

    /**
     * 反射拿到泛型接口的实现类的实际泛型类型
     */
    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结束");
    }

输出结果是:

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

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

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

public class MessageSender <T>{

}

public class SmsMessage extends MessageSender<String>{
}

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

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结束");

    }

 输出结果是:

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

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

我们定义了一个verify方法:

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){
    }



}

输出结果是:

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

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

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;


}

输出结果是:

testFieldGenericActualType开始
获取字段上泛型参数的实际类型:class java.lang.String
testFieldGenericActualType结束

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值