关于泛型通配符边界的疑惑及解疑

<? extends someclass>为什么可以get而不能set?

void set(? extends someclass);

? extends someclass get(); 

  我们使用通配符通常是希望某一个实例可以向上转型 例:

List<Animal> list = new ArrayList<Dog>() //compile error 

List<? extends Animal> list = new ArrayList<Dog>()  //compile ok

  这些是基本的概念,在这儿我就不再概述为什么了,我们要讲的是为什么上界限定(? extends someclass)使用set方法

编译错误,而使用get方法却是安全的呢?

0)现在假想我们有一个Animal基类和若干子类(这些子类都继承自Animal)

  让我们先考虑一下数组,假如你以如下的形式建立了一个数组.

Animal[] ani = new Dog[](10); //compile ok

  利用了向上转型的多态思想,这是完全合法的 现在我们设想向里面添加元素。

ani[0] = new Dog() //compile ok ,runtime ok

ani[1] = new Animal() //compile ok , runtime error

  我们知道现在操纵的是Dog类型的数组,但是编译器不知道(只有在运行时,ani引用才和dog数组建立联系),编译的时候编译器没有理由会拒绝存放Animal类型的对象,因为他本身就是一个Animal类型的引用。

  数组拥有特殊的保护机制,即使在编译时期插入了错误的对象,运行时也能发现并抛出这些异常,所以也没必要为此担心什么。

1)带通配符的set方法

现在假设你运用的是泛型,你能不能这样做呢? 现在考虑如下例子

 List<? extends Animal> list = new ArrayList<Dog>() //compile ok

这也是向上转型。

但有一点和数组不同的是,数组在编译阶段就确定了他是什么类型的数组引用(如上例是Animal类型的数组引用),而带泛型的List呢?他只知道他是一个某类型的List引用,只知道这个“某类型”是继承自Animal的类,具体是Dog,Cat,还是Monkey呢,他一无所知。

你可能会提出疑问,后面不是跟了 new ArrayList<Dog>() 吗,这不是在告诉他他是一个Dog类型的ArrayList引用吗?很遗憾,编译器没有那么聪明,这些只会在运行时建立联系,然而运行时的类型擦除又让他们携带的信息烟消云散,你也就无法期待这些东西在运行时会给你什么惊喜了。

那如果想向我们刚建好list里面添加元素呢 如add(new Dog()) 或者add(new Animal())   (和set一样,在此以add为例更好)

list.add(new Dog())    //compile error

list.add(new Animal()) //compile error

编译器拒绝一切为其添加元素的操作(传参操作),为什么?因为 List<? extends Animal> list 无法确定他具体是什么类,就像List<Animal>只能为其添加Animal及Animal的子类元素一样,你一个连具体是什么类都不知道的引用,编译器自然认为任何添加都是不安全的。

让我们再举个容易理解的例子,我们暂时仅仅只观察这个式子-------List<? extends Animal> 现在我们假设?是Cat,那么我们能做些什么?

我们能向里面添加 Cat和Cat的子类元素,但是我们不能添加Dog,monkey甚至是Animal元素。

那现在返回来,编译器无法得知 ? 具体是什么类型,那 ?可能是Cat,也可能是Dog 或者其他的继承自Animal的类,我们又怎么能确定哪些add是安全的,哪些add是非法的呢?

所以我们自然无法使用add或者set方法。

2) get方法的合理性

我们知道get方法返回一个值,这个值只要是确定的编译器就可以接受,现在考虑如下例子

         
         List<Cat> test = new ArrayList<Cat>(); 
 test.add(new Cat());
 List<? extends Animal> list = test; 
 Animal ani = list.get(0); //compile ok,runtime ok

get方法为什么合理? 因为他有一个确定的返回值。 ? extends Animal 的返回值一定是一个Animal类型的 如果你对这句话有异议,那我建议你再回去温习一下有关多态的知识,这确实是多态的一个体现,不管你?是代表Cat Dog 还是Monkey 这些类的共通点就是他们都是继承自Animal的,这点编译器心知肚明,自然也就不会有任何异议和不确定性,所以get方法确实是合理的





















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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值