effective java(28) 之利用有限制通配符来提升API的灵活性
2017-10-28 23:15
253 查看
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:
在使用方法pushAll时,添加src,其中的数据类型要跟当前的Stack完全相同,这样才可以使用。
比如,Stack<Number>,那么src的类型就只能是Iterable<Number>,不能是Iterable<Integer>。因为,Iterable<Number>与Iterable<Integer>并不是同一个类型。
那么,如果要实现一种效果,可以添加的类型是Stack中元素类型的子类型,而不一定使用完全相同的类型。可以通过有限制的通配符来实现:
3、
要实现一个功能,将堆栈中的元素弹出来,保存到一个容器中。也就是实现popAll这个API。
使用这个API是有要求的,那就是容器的类型要完全跟当前的Stack的类型一致。
那么,假设,我们像堆栈中的元素可以存放在容器Collection<Object>中,那么,该如何重新定义popAll方法?
使用super关键字。
修改后的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都是消费者。
每天努力一点,每天都在进步。
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都是消费者。
每天努力一点,每天都在进步。
相关文章推荐
- Item 28 利用有限制通配符来提升API的灵活性
- EffectiveJava(28)怎么利用有限制的通配符类型来提升API的灵活性
- 利用有限制通配符来提升API的灵活性。
- 利用有限制通配符来提升API的灵活性
- 第28条:利用有限制通配符来提升API的灵活性
- 第二十八条:利用有限制通配符来提升API的灵活性
- 第28条:利用有限制通配符来提升API的灵活性
- (28):利用有限制通配符来提高API的灵活性
- 第28条 泛型——利用有限制通配符来提升API的灵活性
- 第二十八条:利用有限通配符提升API的灵活性
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)
- Effective Java 第三版——31.使用限定通配符来增加API的灵活性
- 利用有限通配符提供API灵活性
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)
- Effective Java(数组和泛型的实现方式、用无限制的通配符提高API的灵活性)