下面先举出一个泛型栈的例子:
class Stack<E>{
private List<E> element;
private int index;
private int defalut_capacity;
public Stack() {
element = new ArrayList<E>(defalut_capacity);
}
public void push(E e) {
element.add(e);
index++;
}
public E pop() {
return element.get(--index);
}
}
这时,我们出现了一个需求,想在push方法中push一个E的子类,pop方法pop出来的对象用其父类去接收。
public class test4 {
public static void main(String[] args) {
Stack<Father> stack1 = new Stack<Father>();
stack1.push(new Son());
Stack<Son> stack2 = new Stack<Son>();
//假设stack2有元素
Father father = stack2.pop();
}
}
完全没问题。
需求又来了,我们要添加pushAll和popAll方法,pushAll将集合
List< E >每个元素push进去(包括E的子类),popAll把栈中元素pop到一个List< E >中(或者E的父类)。
于是我们添加了两个方法:
public void pushAll(Collection<E> src) {
for(E e : src) {
push(e);
}
}
public void popAll(Collection<E> dst) {
while(index>0) {
dst.add(pop());
}
}
好,我们来运行一下:
//son是father的子类
public static void main(String[] args) {
Stack<Father> stack1 = new Stack<Father>();
List<Son>sons = new ArrayList<Son>();
//编译错误
//The method pushAll(Collection<Father>) in the type Stack<Father>
//is not applicable for the arguments (List<Son>)
stack1.pushAll(sons);
Stack<Son> stack2 = new Stack<Son>();
List<Father>Fathers = new ArrayList<Father>();
//编译错误
//The method pushAll(Collection<Father>) in the type Stack<Father>
//is not applicable for the arguments (List<Son>)
*/
stack2.pushAll(Fathers);
}
果断编译错误,原因很简单,参数化类型是不可变的,也就是说List< Son >不是List< Father >的子类,所以无法多态。
解决方法:
public void pushAll(Collection<? extends E> src) {
for(E e : src) {
push(e);
}
}
public void popAll(Collection<? super E> dst) {
while(index>0) {
dst.add(pop());
}
}
这样就ok了,也就是说利用有限制通配符能够让不可变的泛型具有了“多态”的感觉。
PECS(Producer-extends,Consumer-super)原则
在stack例子中
pushAll方法中src参数生产对象给stack,所以src是生产者,也就是应该用< ? extends XX >
popAll方法中des参数消费stack的对象,所以des是生产者,也就是应该用< ? super XX >