Java 泛型: 什么是PECS(Producer Extends, Consumer Super)
2015-01-12 14:12
267 查看
最近在看《Java in a Nutshell》,其中提到了PECS,但英文的解释看的晕晕的:
Type covariance
This means that the container types have the same relationship to each other as the payload types do. This is expressed using the
extends keyword.
Type contravariance
This means that the container types have the inverse relationship to each other as the payload types. This is expressed using the
super keyword.
就找了篇中文资料看下,转载自:http://www.java-cn.com/club/article-8534-1.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》的第五章。
Type covariance
This means that the container types have the same relationship to each other as the payload types do. This is expressed using the
extends keyword.
Type contravariance
This means that the container types have the inverse relationship to each other as the payload types. This is expressed using the
super keyword.
就找了篇中文资料看下,转载自:http://www.java-cn.com/club/article-8534-1.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泛型中?和T有什么区别?
- 从头认识java-13.11 对比数组与泛型容器,观察类型擦除给泛型容器带来什么问题?
- Java 泛型 PECS
- java 里 泛型中 <T>代表什么类型
- 从头认识java-13.11 对照数组与泛型容器,观察类型擦除给泛型容器带来什么问题?
- Java中集合泛型带来了什么好处?
- 0072 Java中的泛型--泛型是什么--泛型类--泛型方法--擦除--桥方法
- Java千百问_05面向对象(012)_泛型是什么
- Java通过反射获取泛型实际类型总结(什么可获取,什么不可获取)
- Java里泛型有什么作用
- java中的 泛型和?组合使用时什么意思
- 牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现
- 在JAVA中返回类型使用泛型T和Object有什么区别?
- java中什么是泛型
- 初学Java注意什么?
- java之旅(一)什么是java