effective java(28) 之利用有限制通配符来提升API的灵活性

effective java 之利用有限制通配符来提升API的灵活性


1、如第25条所述,参数化类型是 不可变的(invariant)。换句话说,对于任何两个截然不同的类型tyle1和type2来说,List<Type1>既不是List<Type2>的子类型,也不是他的超类型。
虽然List<String>不是List<Object>的子类型,这与直觉相悖,但是实际上很有意义。你可以将任何对象放进一个List<Object>中,却只能将字符串放进<String>中。
同样我们声明了一个List<Number>的变量,不仅仅可以把Number类型的对象放入其中,也可以把Integer和Long等类型的对象放入其中。
之所有可以这样做,是因为有限制的通配符给我们带来了便利。

2、有时候,我需要的灵活性要比不可变类型所能提供的更多。考虑第26条中的堆栈下面就是他的公共API:
	publicclass Stack<E>{  
	   public Stack();  
	   public void push(E e);  
	   public E pop();  
	   public boolean isEmpty();  
	   public voidpushAll(Iterable<E> src);  
	} 

在使用方法pushAll时,添加src,其中的数据类型要跟当前的Stack完全相同,这样才可以使用。
比如,Stack<Number>,那么src的类型就只能是Iterable<Number>,不能是Iterable<Integer>。因为,Iterable<Number>与Iterable<Integer>并不是同一个类型。
那么,如果要实现一种效果,可以添加的类型是Stack中元素类型的子类型,而不一定使用完全相同的类型。可以通过有限制的通配符来实现:
	public classStack<E>{  
	   public Stack();  
	   public void push(E e);  
	   public E pop();  
	   public boolean isEmpty();  
	   public voidpushAll(Iterable<? extends E> src);  
	}  

3、
	publicclass Stack<E>{  
	   public Stack();  
	   public void push(E e);  
	   public E pop();  
	   public boolean isEmpty();  
	   public voidpushAll(Iterable<? extends E> src);  
	   public voidpopAll(Collection<E> dst);  
	} 	

要实现一个功能,将堆栈中的元素弹出来,保存到一个容器中。也就是实现popAll这个API。
使用这个API是有要求的,那就是容器的类型要完全跟当前的Stack的类型一致。
那么,假设,我们像堆栈中的元素可以存放在容器Collection<Object>中,那么,该如何重新定义popAll方法?
使用super关键字。
	publicclass Stack<E>{  
	   public Stack();  
	   public void push(E e);  
	   public E pop();  
	   public boolean isEmpty();  
	   public voidpushAll(Iterable<? extends E> src);  
	   public voidpopAll(Collection<? super E> dst);  
	}  	

修改后的popAll方法,可以保存堆栈弹出的元素的容器类型是这样的,容器类型是Stack元素类型的父类。


4、使用了上述的通配符,会提高API的灵活性,让它可以接受更多的类型。
1)pushAll 是数据的生产者:
对生产者的进参数使用 <? extends E>,可以接受更多的类型,而不是只是E这种类型,可以接受E及其子类的类型。
2)popAll是数据的消费者:
对消费者出参数使用<? super E>,可以让堆栈的数据保存在多种类型的容器中,而不只是保存在Collection<E>。它可以保存在类型是E的父类的容器中。

下面的助记符便于让你记住要使用哪种通配符类型类型:
PESC表示producter-extends, consumer-super.
如果参数化类型表示一个T生产者,就使用<? extends T>;如果它表示一个T消费者,就使用<? super T>。


5、总之,在API中使用通配符类型虽然比较需要技巧,但是使API变得灵活的多。
如果在写的是一个将被广泛使用的类库,则一定要适当地利用通配符类型。
记住基本的原则:PECS,还要记得所有的comparable和comparator都是消费者。



每天努力一点,每天都在进步。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

powerfuler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值