(28):利用有限制通配符来提高API的灵活性

正如我们所知参数化类型是不可变的,也就是说List<type1>和List<type2>是没有任何关系的即使type1和type2是父子类的关系。当type1参数作为泛型参数时,type2即使是type1的子类,也不能作为泛型参数。看下面的例子:

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

我们添加增加一个新方法,用于顺序插入元素到栈中

public void pushAll(Iterable<E> src) {  
    for (E e: src)  
public static <T extends Comparable<? extends T>> max(  
        List<? extends T> list) {  
    Iterator<T> i = list.iterator();  
    T result = i.next();  
    while (i.hashNext()) {  
        T t = i.next();  
        if (T.compareTo(result) > 0)  
            result = t;  
    }  
    return result;  
}  

push(e); }

这个方法编译起来是没问题的。但是有个局限性,假设有个Stack<Number>,那么pushAll只能插入Number类型的数,即使Integer是Number子类也不能插入。
幸运 的是Java提供了一种解决方法,称为有限制的通配符类型来处理这种情况。使用有限制的通配符Iterable<? extends E>即可解决这个问题(注意,确定了子类型后,第一个类型便都是自身的子类型),修改后的程序如下:

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

对应的假如我们想写一个popAll() 此时Iterable<? extends E>作为参数类型是不可以的,我们应该用Collection<? super E>如下:

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



如果参数化类型表示一个T生产者,就使用<? extends T>;如果它表示一个T消费者,就使用<? super T>。通俗点讲,就是如果是只读的就用<? super T>,如果是只写的就用
<? extends T>。如果是参数需要可写可读的,就不要用通配符。

看如下的max方法

public static <T extends Comparable<? extends T>> max(  
        List<? extends T> list) {  
    Iterator<T> i = list.iterator();  
    T result = i.next();  
    while (i.hashNext()) {  
        T t = i.next();  
        if (T.compareTo(result) > 0)  
            result = t;  
    }  
    return result;  
}  
这段段代码会报错,意味着list.iterator没有返回Iterator<T>,因为它返回了T的一个子类型,知道了错误的原因,那就使用T的一个子类型来修改返回类型,代码如下

public static <T extends Comparable<? extends T>> max(  
        List<? extends T> list) {  
    Iterator<? extends T> i = list.iterator();  
    T result = i.next();  
    while (i.hashNext()) {  
        T t = i.next();  
        if (T.compareTo(result) > 0)  
            result = t;  
    }  
    return result;  
}  
总之,在API中使用通配符类型虽然比较需要技巧,但是使API变得灵活的多,如果在写的是一个将被广泛使用的类库,则一定要适当地利用通配符类型,记住基本的原则:所有的comparable和comparator都是消费者。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值