Java 泛型 lt;super gt 2017T>中 super gt 2017怎么 理解?与 extends 有何不同

Java 泛型: 什么是PECS(Producer Extends, Consumer Super) - ImportNew
什么是PECS?
PECS指“Producer Extends,Consumer Super”。换句话说,如果参数化类型表示一个生产者,就使用&? extends T&;如果它表示一个消费者,就使用&? super T&,可能你还不明白,不过没关系,接着往下看好了。
下面是一个简单的Stack的API接口:
public class
public Stack();
public void push(E e):
public E pop();
public boolean isEmpty();
假设想增加一个方法,按顺序将一系列元素全部放入Stack中,你可能想到的实现方式如下:
public void pushAll(Iterable&E& src){
for(E e : src)
假设有个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)
这样就可以正确编译了,这里的&? 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、Python、云计算,移动互联网。(新浪微博:)
运行成功,不错。
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:@
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2017 ImportNew泛型中? super T和? extends T的区别
来源:博客园
经常发现有List、Set的声明,是什么意思 呢?表示包括T在内的任何T的父类,表示包括T在内的任何T的子类,下面我们 详细分析一下两种通配符具体的区别。 extends List foo3的通配符声明,意味着以下的赋值是合法的: // Number "extends" Number (in this context) List foo3 = new ArrayList(); // Integer extends Number List foo3 = new ArrayList(); // Double extends Number List foo3 = new ArrayList(); 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你可以读取到Number,因为以上的列表要么包含Number元素,要么包含Number的类元素。 你不能保证读取到Integer,因为foo3可能指向的是List。 你不能保证读取到Double,因为foo3可能指向的是List。 写入操作过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢? 你不能插入一个Integer元素,因为foo3可能指向List。 你不能插入一个Double元素,因为foo3可能指向List。 你不能插入一个Number元素,因为foo3可能指向List。 你不能往List中插入任何类型的对象,因为你不能保证列表实际指向的类型是什么,你并不能保证列表中实际存储什么类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。 super 现在考虑一下List。 List foo3的通配符声明,意味着以下赋值是合法的: // Integer is a "superclass" of Integer (in this context) List foo3 = new ArrayList(); // Number is a superclass of Integer List foo3 = new ArrayList(); // Object is a superclass of Integer List foo3 = new ArrayList(); 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你不能保证读取到Integer,因为foo3可能指向List或者List。 你不能保证读取到Number,因为foo3可能指向List。 唯一可以保证的是,你可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)。 写入操作通过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢?你可以插入Integer对象,因为上述声明的列表都支持Integer。 你可以插入Integer的子类的对象,因为Integer的子类同时也是Integer,原因同上。 你不能插入Double对象,因为foo3可能指向ArrayList。 你不能插入Number对象,因为foo3可能指向ArrayList。 你不能插入Object对象,因为foo3可能指向ArrayList。 PECS 请记住PECS原则:生产者(Producer)使用extends,消费者(Consumer)使用super。 生产者使用extends 如果你需要一个列表提供T类型的元素(即你想从列表中读取T类型的元素),你需要把这个列表声明成,比如List,因此你不能往该列表中添加任何元素。 消费者使用super 如果需要一个列表使用T类型的元素(即你想把T类型的元素加入到列表中),你需要把这个列表声明成,比如List,因此你不能保证从中读取到的元素的类型。 即是生产者,也是消费者 如果一个列表即要生产,又要消费,你不能使用泛型通配符声明列表,比如List。 例子 请参考java.util.Collections里的copy方法(JDK1.7): 我们可以从Java开发团队的代码中获得到一些启发,copy方法中使用到了PECS原则,实现了对参数的保护。
免责声明:本站部分内容、图片、文字、视频等来自于互联网,仅供大家学习与交流。相关内容如涉嫌侵犯您的知识产权或其他合法权益,请向本站发送有效通知,我们会及时处理。反馈邮箱&&&&。
学生服务号
在线咨询,奖学金返现,名师点评,等你来互动& 共9页&&nbsp&&nbsp&&nbsp...&&&&nbsp&
熟悉的领域
电子邮箱:
手机号码:
对Ta感兴趣的人
最近一周被访问了次
被关注:5人拒绝访问 | www. | 百度云加速
请打开cookies.
此网站 (www.) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(3c4382-ua98).
重新安装浏览器,或使用别的浏览器JAVA泛型的? extends和? super的比较
在JDK1.5之后可以使用泛型,通常可以在下面的地方使用.
A,泛型类声明,如public class GeneralT&A&
B,泛型接口声明,如public interface GenIntf&A&
C,泛型方法声明,如
public &T extends BaseCls& void thisIsT(List&T& list, T e) {
&&& list.add(e);
D,泛型构造器(constructor)声明,如 GeneralT&BaseCls& pgt = new GeneralT&BaseCls&();
在这里主要介绍一下? extends和? super的区别.
1,? extends叫做向上造型.
ArrayList&? extends BaseCls& list1 = new ArrayList&BaseCls&();
意味着这个list1里面放的都是BaseClse的子类,保证你可以通过list.get(index)
得到的类都是BaseCls或者BaseCls的子类.
BaseCls cls = list1.get(0);//合法的
list1.add(new BaseCls());或者list1.add(new CldCls());都是不合法的.
这里面是不能通过add函数放东西进去的,那这样有什么用呢.
一般来讲,定义成? extends BaseCls的参数通常只能用来从里面取数据.
如下downbound方法可以接受? extends BaseCls类型的list
public void downbound(List&? extends BaseCls& list) {&&&
&&& for(BaseCls cls:list){
&&&&&&& cls.func();
&&& }&&&&&&&
ArrayList&BaseCls& list1 = new ArrayList&BaseCls&();
ArrayList&CldCls& list2 = new ArrayList&CldCls&();
downbound(list1);和downbound(list2);都是合法的.
2,? super BaseCls叫做向下造型.
ArrayList&? super BaseCls& list2 = new ArrayList&BaseCls&();
意味着这个list2里面只能放BaseClse或者它的子类.
list2.add(new BaseCls());或者list2.add(new CldCls());都是合法的.
list2.get(index)返回的是Object类型,因为不知道是那个具体类.
限制了放进去的对象的类型,为什么取的时候不是BaseCls呢,这里不理解...
public void upperbound(List&? super BaseCls& list) {
&&& list.add(new BaseCls()
&&& list.add(new CldCls());
作者:kkdelta

我要回帖

更多关于 lt super51 的文章

 

随机推荐