java中的泛型擦除

众所周知,java中泛型是 “编译时擦除” 的,但并不总是会被擦出。例如spring4中的泛型依赖注入就是通过动态获取泛型参数,对依赖进行匹配的。

Class类 对泛型参数的获取提供了两个API
returnmethoddesc
TypegetGenericSuperclass获取直接父类的(带泛型参数)的类型
Type[]getGenericInterfaces获取实现接口的(带泛型参数)的类型
通过API可以确定的一点是:Java中要想获取泛型参数,只能获取父类或父接口的,而不能直接获取自己的。

何时会被擦?

定义测试类
class TestGeneric<T>{

}
该类编译后的字节码
public class org.java.springTest.TestGeneric<T extends java.lang.Object> extends java.lang.Object
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:

   #9 = Utf8               <T:Ljava/lang/Object;>Ljava/lang/Object;
  #14 = Utf8               java/lang/Object

Signature: #9                           // <T:Ljava/lang/Object;>Ljava/lang/Object;
SourceFile: "TestGeneric.java"
可以看到 倒数第二行的注释 <T:Ljava/lang/Object;> T被编译后是Object类型。这是正常的,因为TestGeneric类的不同实例,泛型参数都可以不同。而java并没有为每一个实例保留其指定的泛型类型,也没有提供任何API。
  • 一个证明泛型擦除的例子
    List<Integer> list = new ArrayList<Integer>();
    Method m =  list.getClass().getMethod("add",Object.class);
    m.invoke(list, "abcd");
    System.out.println(list.get(0));    //输出 abcd

何时不会被擦除?

定义测试类
interface IBase<T1,T2>{

}

class Base<T1,T2> { }

class Child extends Base<Double,Integer>  implements IBase<String,Long>{ 
    public void show() {
        System.out.println(this.getClass().getGenericSuperclass());
    }
}
编译后的字节码
class Child extends Base<java.lang.Double, java.lang.Integer> implements IBase<java.lang.String, java.lang.Long>
Constant pool:
     LBase<Ljava/lang/Double;Ljava/lang/Integer;>;LIBase<Ljava/lang/String;Ljava/lang/Long;>;

Signature: #10                          // LBase<Ljava/lang/Double;Ljava/lang/Integer;>;LIBase<Ljava/lang/String;Ljava/lang/Long;>;
SourceFile: "Base.java"
可以看出,在子类继承父类实现接口并指定了泛型参数后,编译器会保留我们的泛型参数。

如何得到泛型参数?

  • 一个获取泛型参数的例子
    //获得声明的父类泛型参数
    ParameterizedType ts = (ParameterizedType)Child.class.getGenericSuperclass();
    Stream.of(ts.getActualTypeArguments()).forEach(System.out::println);

    //获得声明的父接口泛型参数
    Type [] type2 =  Child.class.getGenericInterfaces();
    Arrays.stream(type2).forEach(
            (tt)-> 
                Arrays.stream(((ParameterizedType)tt).getActualTypeArguments()).forEach(System.out::println)
    );

得到泛型参数有什么用?

一个典型的例子就是Spring4的泛型依赖注入,Spring4 通过 获取泛型参数 来匹配 有依赖的类。Spring4不在本章的讲解范畴,可以查阅本人在知乎提的问题 spring4的泛型依赖注入是什么原理?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值