美文网首页
泛型通配:PECS

泛型通配:PECS

作者: 树心图物 | 来源:发表于2019-04-22 21:28 被阅读0次

PECS指“Producer Extends,Consumer Super”。换句话说,如果参数化类型表示一个生产者,就使用<? extends T>;如果它表示一个消费者,就使用<? super T>,java中的泛型其实是为了进行类型限定和检查的,这个生产者和消费者指的就是泛型所限定的类型变量或集合,下面结合例子进行说明。

下面是一个简单的Stack的API接口:

public class  Stack<E>{
    public Stack();
    public void push(E e):
    public E pop();
    public boolean isEmpty();
}

假设想增加一个方法,按顺序将一系列元素全部放入Stack中,你可能想到的实现方式如下:

public void pushAll(Iterable<E> src){
    for(E e : src)
        push(e)
}

假设有个Stack<Number>,想要灵活的处理Integer,Long等Number的子类型的集合

Stack<Number> numberStack = new Stack<Number>();
Iterable<Integer> integers = ....;
numberStack.pushAll(integers);

此时代码编译无法通过,因为对于类型Number和Integer来说,虽然后者是Number的子类,但是对于任意Number集合(如List<Number>)不是Integer集合(如List<Integer>)的超类,因为泛型是不可变的。

幸好java提供了一种叫有限通配符的参数化类型,pushAll参数替换为“E的某个子类型的Iterable接口”:

public void pushAll(Iterable<? extends E> src){
    for (E e: src)
        push(e);
}

这样就可以正确编译了,这里的<? extends E>就是所谓的 producer-extends。这里泛型限定的Iterable就是生产者,要从中迭代访问元素,要使用<? extends E>。因为Iterable<? extends E>可以容纳任何E的子类。在执行操作时,可迭代对象的每个元素都可以当作是E来迭代。此时不能向泛型限定的src中加入元素,因为src的具体类型可能是E的一个分支子类,而如果向其中加入E或其他分支子类类型的元素都是不合法的,又因为src本身是一个不确定泛型,所以加入任何元素都有可能出错,除了null,这就是生产者的只能取出访问不能存入特性了。

与之对应的是:假设有一个方法popAll()方法,从Stack集合中弹出每个元素,添加到指定集合中去。

public void popAll(Collection<E> dst){
       if(!isEmpty()){
                dst.add(pop());
        }
}

假设有一个Stack<Number>和Collection<Object>对象:

Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ...;
numberStack.popAll(objects);

同样上面这段代码也无法通过,解决的办法就是使用Collection<? super E>。这里的objects是消费者,因为是添加元素到objects集合中去。使用Collection<? super E>后,无论objects是什么类型的集合,满足一点的是他是E的超类,所以不管这个参数化类型具体是什么类型都能将E装进objects集合中去,而要取出的话也只能使用Object来接了,因为泛型限定的dst除了能确定是Object的子类,其他无法确定合法,这是消费者只能存不能取的特性。

总结:

如果你是想遍历collection,并对每一项元素操作时,此时这个集合时生产者(生产元素),应该使用 Collection<? extends Thing>.
如果你是想添加元素到collection中去,那么此时集合时消费者(消费元素)应该使用Collection<? super Thing>

相关文章

  • 泛型通配:PECS

    PECS指“Producer Extends,Consumer Super”。换句话说,如果参数化类型表示一个生产...

  • Android基础难点-泛型

    泛型上下限的读写模式是什么(或者泛型的PECS模式) PECS指的是Producer Extends, Consu...

  • Java泛型

    1. 泛型通配符与PECS 为什么要使用泛型通配符和边界 List泛型转换需要用到通配符 ? “装A的List” ...

  • Java 泛型 PECS

    在stackoverflow上看到两篇关于java泛型 PECS 的问答: Difference between ...

  • 【JAVA】浅谈Java范型

    1.Java泛型是什么?2.通常的泛型的写法示例3.类型擦除4.为什么要使用Java泛型5.通过示例了解PECS原...

  • [java]你应该知道的泛型(Generic)与PECS原则

    本文通过一个水果篮子的例子,试图帮助读者理解泛型使用中的PECS原则。本文假设读者对泛型以及泛型通配符有基础性的了...

  • JAVA泛型总结

    泛型命名 泛型一些约定俗成的命名: 上界通配符 可以使用上界通配符来缩小类型参数的类型范围。 下界通配符 下界通配...

  • JAVA范型<? extends __> <

    目录 一. 泛型概念的提出(为什么需要泛型)? 二.什么是泛型? 三.自定义泛型接口、泛型类和泛型方法 四.类型通...

  • 泛型基础二

    如果不明白为什么要使用泛型,使用泛型的好处,以及泛型类,泛型接口,泛型方法等知识,请移步泛型基础一 通配符 上界通...

  • 『Java』泛型中的PECS原则

    Java编程中有时我们要用到不确定的元素,通常用通配符"?"表示,其中" ? extends T "叫"上界通配符...

网友评论

      本文标题:泛型通配:PECS

      本文链接:https://www.haomeiwen.com/subject/fqbeeqtx.html