JAVA泛型通配符 extends 和 super

在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 Strings
String 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)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值