什麼是PECS?java
PECS指「Producer Extends,Consumer Super」。換句話說,若是參數化類型表示一個生產者,就使用;若是它表示一個消費者,就使用,可能你還不明白,不過不要緊,接着往下看好了。code
下面是一個簡單的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的子類型的集合io
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接口」:class
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來操做。泛型
與之對應的是:假設有一個方法popAll()方法,從Stack集合中彈出每一個元素,添加到指定集合中去。object
public void popAll(Collection<E> dst){ if(!isEmpty()){ dst.add(pop()); } }
假設有一個Stack<Number>和Collection<Object>對象:List
Stack<Number> numberStack = new Stack<Number>(); Collection<Object> objects = ...; numberStack.popAll(objects);
一樣上面這段代碼也沒法經過,解決的辦法就是使用Collection<? super E>。這裏的objects是消費者,由於是添加元素到objects集合中去。使用Collection<? super E>後,不管objects是什麼類型的集合,知足一點的是他是E的超類,因此無論這個參數化類型具體是什麼類型都能將E裝進objects集合中去。
若是你是想遍歷collection,並對每一項元素操做時,此時這個集合時生產者(生產元素),應該使用 Collection<? extends Thing>.
若是你是想添加元素到collection中去,那麼此時集合時消費者(消費元素)應該使用Collection<? super Thing>.