Effective-Java item 30

第30条款中有类似这样一段代码:

测试代码块1

public class GenericTest 
{
    private static UnaryOperator<Object> IDENTITY_FN= t->t;
    @SuppressWarnings("unchecked")
    public static <T> UnaryOperator<T> identityFunction() {
        return (UnaryOperator<T>) IDENTITY_FN;
    }
    public void test1()
    {
        UnaryOperator<String> upString=identityFunction();
        out.println(upString.apply("hehe"));
    }
}

输出:

hehe

这样的代码为何能运行成功?
分析:
Java泛型推导机制,根据函数返回值能推断出T的类型,这行代码

UnaryOperator<String> upString = identityFunction();

让编译器推导出函数identityFunction中的泛型T是String类型,因此

return (UnaryOperator) IDENTITY_FN;

这行代码将一个List<Object> 转换成一个List<String>,但是为何能在运行时强制转换成功呢?
这要涉及Java泛型的实现方式,Java泛型是通过编译时擦除泛型信息来实现的,通过将上述代码编译后再反编译回来,可以看到泛型信息是怎么被擦除和使用的。

测试代码块2

public class GenericTest {

   private static UnaryOperator IDENTITY_FN = (param1) -> {
      return var0;
   };
   
   public static UnaryOperator identityFunction() {
      return IDENTITY_FN;//并没有强制转换
   }
   
   public void test1() {
      UnaryOperator var1 = identityFunction();
      System.out.println((String)var1.apply("hehe"));//强制转换
   }
}

  可以看到,所有的泛型信息都没了,且并没有所谓的强制转换过程,UnaryOperator&ltl;String> 和UnaryOperator<Object>并没有区别,在这里都是UnaryOperator,而所有需要调用UnaryOperator&ltl;String>类的方法的地方,返回值都加了一个(String)的强制类型转换。

  特别的,如果一个类中有一个T类型的属性,那么编译后会变为Object类型,并且在使用到它的地方,会加一个 (T) 这样的强制类型转换。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值