(12) Java 中泛型擦除之后,【运行时】还可以获取到哪些泛型相关信息?

1、首先了解什么是泛型擦除?

所谓的泛型擦除(Type Erasure),就是指在编译时,JVM 编译器会将所有的泛型信息都擦除掉,变成原始类型,一般是将泛型的类型参数替换成具体类型的上限或下限 (如果没有指定上界,则默认为Object)。

例如,看下列代码

  static class BasicService<T> {
        void save(T t) {
            System.out.println("执行save方法,保存 " + t);
        }
    }

在运行时执行的代码就是这样的

  static class BasicService<Object> {
        void save(Object t) {
            System.out.println("执行save方法,保存 " + t);
        }
    }

2、回归正题,在运行时能够拿到那些泛型相关信息呢?

结论:

1、当没有具体化参数类型时,只能够是被当做是 Object 或者 extends 上限。

2、当有具体化类型参数,在下面的情况下可以通过反射拿到。

  • 继承泛型父类

  • 实现泛型接口

  • 成员变量(字段)

  • 方法参数、返回值、异常声明

3、举例说明

1、当没有具体化时,如 BasicService<T> ,方法 save 中的参数 t 只能够使用 Object 中的方法。

 

当泛型 T 使用了 extends 类型上限,如下,那么泛型 T 就是 Person 类的子类,save 中的参数 t 就可以使用 Person 类中的方法了。

    static class Person {
        public void save() {
        }
    }
​
    static class BasicService<T extends Person> {
        void save(T t) {
​
            System.out.println("执行save方法,保存 " + t);
        }
    }

 

2、具体化

2.1、继承泛型父类,如下在运行时是可以拿到 TeacherService 中的泛型类型的。

     public class Teacher extends Person {
​
    }
  
  
  static class TeacherService extends BasicService<Teacher> {
​
    }

2.2、实现泛型接口,和 2.1 类似

2.3、当泛型字段是成员变量时也可以获取,例如下代码中的 x 字段。

   static class BasicService<T extends Person> {
        void save(T t) {
            System.out.println("执行save方法,保存 " + t);
        }
​
        List<String> x;
​
       List<Random> y(List<Number> z,Set<Boolean> s) {
            return null;
        }
    }

2.4、方法参数和返回值中的泛型类型也可以获取到,例如上面代码中的 y 方法。

特别说明,当泛型具体化时,但是不满足那四个条件也是不能够拿到泛型类型的,例如下代码中,是不能够拿到 stringList 的泛型类型的。

   public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        
    }

4、获取实现

4.1、继承泛型父类

  
    Type type = TeacherService.class.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) type;
            Type[] types = pt.getActualTypeArguments();
            System.out.println("types = " + Arrays.toString(types));
        }
​
​
//运行结果
types = [class com.zjj.learn.mls.s1.day12.Test12$Teacher]
​
Process finished with exit code 0

4.2、实现泛型接口就是用 getGenericInterfaces() 方法即可

4.3、成员变量

     Field x = BasicService.class.getDeclaredField("x");
        Type xType = x.getGenericType();
        if (xType instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) xType;
            Type[] types = pt.getActualTypeArguments();
            System.out.println("types = " + Arrays.toString(types));
        }
​
// 运行结果
types = [class java.lang.String]
​
Process finished with exit code 0

4.4、方法参数和返回值中的泛型

        Method y = BasicService.class.getDeclaredMethod("y", List.class, Set.class);
        Type yReturnType = y.getGenericReturnType();
        Parameter[] parameters = y.getParameters();
        //获取返回值的类型
        if (yReturnType instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) yReturnType;
            Type[] returnTypes = pt.getActualTypeArguments();
            System.out.println("returnTypes = " + Arrays.toString(returnTypes));
        }
        //获取参数类型
        for (Parameter parameter : parameters) {
            Type parameterizedType = parameter.getParameterizedType();
            if (parameterizedType instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) parameterizedType;
                Type[] yParamType = pt.getActualTypeArguments();
                System.out.println("yParamType = " + Arrays.toString(yParamType));
            }
        }
​
// 运行结果
returnTypes = [class java.util.Random]
yParamType = [class java.lang.Number]
yParamType = [class java.lang.Boolean]
​
Process finished with exit code 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值