java中泛型的不可协变性

泛型的不可协变性

原因

泛型是实现参数化多态的一种形式,泛型通过使用通配符<?>来实现基于某个特定类型的类,这个特定的类型会在编译时被填充,会通过“类型擦除”来实现,例如:

定义了Set的泛型类,我们声明了 Set s1 = new Set(); 在编译阶段,编译器将其转化成为了真正的类Set_Integer,类中的T类型均会被替换为Integer,这也就是类型擦除的含义。

我们在使用泛型时,总会联想到有关继承的协变性或者逆变性,然而泛型实际上是不可协变的,也就是说不存在所谓的继承关系,这其中就和类型擦除的概念相关。

不妨以数组的协变性来举例:我们知道,如果类A是类B的子类,那么A[]是B[]的子类。我们可以写 Object[] obj = new String[]{};

这样的用法会成功通过编译器的检查。而且即便在obj中存放了非string对象,也会在运行时才报异常,静态检查阶段不会抛出异常,Object是String的父类,所以这是合法的。

然而当我们写 ArrayList obj = new ArrayList(); 编译却无法通过,这就是由于泛型的不可协变性的影响:编译器会对泛型进行类型擦除,从而生成新的类 ArrayList_Object 和 ArrayList_Integer,这样的两个类,不存在继承关系,不在继承树上有确切的父子关系,编译器无法new一个obj对象,自然也就出现了异常。

解决办法

那么怎样解决这个问题?我们可以利用通配符<?>中的关键字extends和super,例如 ArrayList<? extends Object> list = new ArrayList; 这样的语句是合法的,Java提供的通配符,一定程度上突破了泛型不可协变性的限制,例如:

// collection1可以存放任何类型  
Collection<?> collection1 = new ArrayList<String>();  
collection1 = newArrayList<Integer>();  
collection1 = newArrayList<Object>();  
   
//collection3表示它可以存放Number或Number的子类    
Collection<? extends Number> collection3 = null;  
collection3 = newArrayList<Number>();  
collection3 = newArrayList<Double>();  
collection3 = newArrayList<Long>();  
   
//collection4表示它可以存放Integer或Integer的父类    
Collection<? super Integer> collection4 = null;  
collection4 = newArrayList<Object>();  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值