[转]Java 泛型: 什么是PECS(Producer Extends, Consumer Super)
2014-02-17 09:17
232 查看
以下内容转自:
原文链接: stackoverflow 翻译: ImportNew.com - 刘志军
译文链接: http://www.importnew.com/8966.html
-----------------------------------------------------------------------
什么是PECS?
PECS指“Producer Extends,Consumer Super”。换句话说,如果参数化类型表示一个生产者,就使用<? extends T>;如果它表示一个消费者,就使用<? super T>,可能你还不明白,不过没关系,接着往下看好了。
下面是一个简单的Stack的API接口:
假设想增加一个方法,按顺序将一系列元素全部放入Stack中,你可能想到的实现方式如下:
假设有个Stack<Number>,想要灵活的处理Integer,Long等Number的子类型的集合
此时代码编译无法通过,因为对于类型Number和Integer来说,虽然后者是Number的子类,但是对于任意Number集合(如List<Number>)不是Integer集合(如List<Integer>)的超类,因为泛型是不可变的。
幸好java提供了一种叫有限通配符的参数化类型,pushAll参数替换为“E的某个子类型的Iterable接口”:
这样就可以正确编译了,这里的<? extends E>就是所谓的 producer-extends。这里的Iterable就是生产者,要使用<? extends E>。因为Iterable<? extends E>可以容纳任何E的子类。在执行操作时,可迭代对象的每个元素都可以当作是E来操作。
与之对应的是:假设有一个方法popAll()方法,从Stack集合中弹出每个元素,添加到指定集合中去。
假设有一个Stack<Number>和Collection<Object>对象:
同样上面这段代码也无法通过,解决的办法就是使用Collection<? super E>。这里的objects是消费者,因为是添加元素到objects集合中去。使用Collection<? super E>后,无论objects是什么类型的集合,满足一点的是他是E的超类,所以不管这个参数化类型具体是什么类型都能将E装进objects集合中去。
总结:
如果你是想遍历collection,并对每一项元素操作时,此时这个集合时生产者(生产元素),应该使用 Collection<? extends Thing>.
如果你是想添加元素到collection中去,那么此时集合时消费者(消费元素)应该使用Collection<? super Thing>
注:此文根据《Effective Java》以及Java Generics: What is PECS? 整理成文。想了解更多有关泛型相关知识,请读者阅读《Effective Java》的第五章。
原文链接: stackoverflow 翻译: ImportNew.com - 刘志军
译文链接: http://www.importnew.com/8966.html
-----------------------------------------------------------------------
什么是PECS?
PECS指“Producer Extends,Consumer Super”。换句话说,如果参数化类型表示一个生产者,就使用<? extends T>;如果它表示一个消费者,就使用<? super T>,可能你还不明白,不过没关系,接着往下看好了。
下面是一个简单的Stack的API接口:
public class Stack<E>{ public Stack(); public void push(E e): public E pop(); public boolean isEmpty(); }
假设想增加一个方法,按顺序将一系列元素全部放入Stack中,你可能想到的实现方式如下:
public void pushAll(Iterable<E> src){ for(E e : src) push(e) }
假设有个Stack<Number>,想要灵活的处理Integer,Long等Number的子类型的集合
Stack<Number> numberStack = new Stack<Number>(); Iterable<Integer> integers = ....; numberStack.pushAll(integers);
此时代码编译无法通过,因为对于类型Number和Integer来说,虽然后者是Number的子类,但是对于任意Number集合(如List<Number>)不是Integer集合(如List<Integer>)的超类,因为泛型是不可变的。
幸好java提供了一种叫有限通配符的参数化类型,pushAll参数替换为“E的某个子类型的Iterable接口”:
public void pushAll(Iterable<? extends E> src){ for (E e: src) push(e); }
这样就可以正确编译了,这里的<? extends E>就是所谓的 producer-extends。这里的Iterable就是生产者,要使用<? extends E>。因为Iterable<? extends E>可以容纳任何E的子类。在执行操作时,可迭代对象的每个元素都可以当作是E来操作。
与之对应的是:假设有一个方法popAll()方法,从Stack集合中弹出每个元素,添加到指定集合中去。
public void popAll(Collection<E> dst){ if(!isEmpty()){ dst.add(pop()); } }
假设有一个Stack<Number>和Collection<Object>对象:
Stack<Number> numberStack = new Stack<Number>(); Collection<Object> objects = ...; numberStack.popAll(objects);
同样上面这段代码也无法通过,解决的办法就是使用Collection<? super E>。这里的objects是消费者,因为是添加元素到objects集合中去。使用Collection<? super E>后,无论objects是什么类型的集合,满足一点的是他是E的超类,所以不管这个参数化类型具体是什么类型都能将E装进objects集合中去。
总结:
如果你是想遍历collection,并对每一项元素操作时,此时这个集合时生产者(生产元素),应该使用 Collection<? extends Thing>.
如果你是想添加元素到collection中去,那么此时集合时消费者(消费元素)应该使用Collection<? super Thing>
注:此文根据《Effective Java》以及Java Generics: What is PECS? 整理成文。想了解更多有关泛型相关知识,请读者阅读《Effective Java》的第五章。
相关文章推荐
- Java 泛型: 什么是PECS(Producer Extends, Consumer Super)
- Java 泛型: 什么是PECS(Producer Extends, Consumer Super)
- java中的 泛型和?组合使用时什么意思
- Java中集合泛型带来了什么好处?
- Java里泛型有什么作用
- 牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现
- Java千百问_05面向对象(012)_泛型是什么
- 0072 Java中的泛型--泛型是什么--泛型类--泛型方法--擦除--桥方法
- 从头认识java-13.11 对照数组与泛型容器,观察类型擦除给泛型容器带来什么问题?
- Java 泛型 PECS
- Java里泛型有什么作用
- 从头认识java-13.11 对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题?
- java中什么是泛型
- java 里 泛型中 <T>代表什么类型
- Java通过反射获取泛型实际类型总结(什么可获取,什么不可获取)
- Java中的泛型是什么 ? 使用泛型的好处是什么?
- 在JAVA中返回类型使用泛型T和Object有什么区别?
- java泛型中?和T有什么区别?
- [Java 10 泛型] 泛型通配符 Info<?> i = new Info<String>(); 在程序中定义没有方法的接口,称之为标识接口
- java中泛型的继承