JAVA泛型通配符 extends 和 super

来源:互联网 发布:淘宝淘金币在哪看 编辑:程序博客网 时间:2024/05/17 02:01

在Java泛型使用中使用“”作为类型的通配符。《Effective
Java》第28条,使用通配符可以提高API的灵活性。
但是通配符也使得泛型的使用变得更加复杂。

泛型类型是不可变

首先泛型类型是不可变的,比如List< String >就不是List< Object >的子类型,而是两个独立的类型。如下

List<String> strs = new ArrayList<String>();List<Object> objs = strs; //编译错误,类型不匹配(imcompatible type)

假如可编译通过的话,会带来新的问题,导致运行时错误

objs.add(1); // Here we put an Integer into a list of StringsString s = strs.get(0); // !!! ClassCastException: Cannot cast Integer to String

所以为了确保运行时类型安全,Java泛型设计成不可变的。

但是这种不可变的泛型类型,又会带来下面问题:定义一个泛型,为“Collection”增加一个addAll方法,如下实现:

interface Collection<E> ... {  void addAll(Collection<E> items);}

那么在将“Collection< Object >”中添加“Collection< String >”,该方法就没法使用了,而理论上应该是合法的,因为String是Object的子类,是可以添加到父类的集合中

void copyAll(Collection<Object> to, Collection<String> from) {  to.addAll(from); // 编译不通过:                   //Collection<String> 不是 Collection<Object>的子类型}

为了解决该问题,Java中使用了类型通配符方式来解决,如下

interface Collection<E> ... {  void addAll(Collection<? extends E> items);}

通配符的上界

? extends T 其中T表示通配符的上界,表示该方法可以接收T以及T的子类。意味着可以安全的读T(所有实例都是T的子类)的实例,但是不能向其添加元素,因为没法确定添加的实例类型跟定义的类型是否匹配。

//Bird Cat都是Animal的子类public void testAdd(List<? extends Animal> list) {  //下面都会报编译错误的   //因为testAdd方法传入的list的类型不确定的,(有可能是List<Cat>,List<Dog>)就没法确保它可以添加下面的全部类型  //若传入“List<Bird>”,只能add(bird),只有②可以添加  //若传入“List<Dog>”,都不能添加  list.add(new Animal("animal")); //①  list.add(new Bird("bird"));    //②  list.add(new Cat("cat"));      //③  for(Animal a:list){    //但是可以读取里面的元素,因为他们都是Animal的子类型  }}

可以理解成:“Collection< String> ”是“Collection< ? extends Object >”的子类型。
这种通配符(wildcard )是通过继承一个范围类(通配符上界,upper bound)来实现类型协变。

通配符的下界

? super T(T表示通配符的下界),表示该方法可以接收T及T的父类参数。意味着可以安全的添加元素,但是不能读取。

    public void testAdd2(List<? super Animal> list){        //可以编译通过,因为传入的T类型肯定是Animal的父类,也是Bird,Cat的父类        list.add(new Animal("animal"));        list.add(new Bird("bird"));        list.add(new Cat("cat"));        for(Animal a:list){            //但是不能读取,因为父类不能转换成子类        }    }

可以理解成:“Collection< ? super String > ”是“Collection< String >”的父类型;可以调用集合将String作为参数的方法(如:add(String) or set(int, String));但当从集合中获取元素时,得到是Objec对象而不是String对象。

PECS

PECS stands for Producer-Extends,Consumer-Super

  • extends

通配符的上界方式,只能从中读取元素,不能添加元素,形象的称为生产者(Producers)

  • super

通配符的下界方式,只能添加元素,没法直接读取下界类型的元素,形象的称为消费者(Consumers)

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 冲马桶水溅出来怎么办 吃了不熟的芋头怎么办 吃多了肚子胀气怎么办 吃多了胃胀气怎么办 红薯吃多了胀气怎么办 裙子贴在腿上怎么办 薄裤子静电吸腿怎么办 雪纺衬衫起静电怎么办 吃烤饼不松软是怎么办 1岁宝宝睡眠不好怎么办 3岁幼儿睡眠不好怎么办 2岁幼儿睡眠不好怎么办 2岁宝宝睡眠不好怎么办 9岁儿童睡眠不好怎么办 3岁宝宝老踢被子怎么办 4岁宝宝老踢被子怎么办 四线锁边机跳线怎么办 引流管伤口洞红怎么办 甘蔗卡在喉咙里怎么办 棉花被子生虫了怎么办 绗缝羽绒服钻毛怎么办 宝珠笔没墨水了怎么办 衣服上画的笔印怎么办 黑笔芯弄衣服上怎么办 圆珠笔油在皮上怎么办 不小心吞了水银怎么办 小孩吃了洗发露怎么办? 脸上被铅笔戳了怎么办 小孩吃了铅笔芯怎么办 小孩把橡皮吃了怎么办 用棉签掏耳朵里面疼怎么办 棉签头掉耳朵里怎么办 黑裤子老是粘毛怎么办 新买的裤子掉色怎么办 黑裤子容易粘毛怎么办 裤子粘了全部毛怎么办 纯棉裤子粘毛了怎么办 裤子粘毛怎么办怎么洗 黑裤子洗白了怎么办 新买床单有味道怎么办 新买的床单扎人怎么办