Effective Java之利用有限制通配符提升API的灵活性(二十八)

下面先举出一个泛型栈的例子:

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 >

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值