AJPFX详解泛型中super和extends关键字
首先,我们定义两个类,A和B,并且假设B继承自A。下面的代码中,定义了几个静态泛型方法,这几个例子随便写的,并不是特别完善,我们主要考量编译失败的问题:
Java代码
public class Generic{
//方法一
public static <T extends A> void get(List<T extends A> list)
{
list.get(0);
}
//方法二
public static <T extends A> void set(List<T extends A> list, A a)
{
list.add(a);
}
//方法三
public static <T super B> void get(List<T super B> list)
{
list.get(0);
}
//方法四
public static <T super B> void set(List<T super B> list, B b)
{
list.add(b);
}
}
编译之后,我们会发现,方法二和方法三没有办法通过编译。按照Thinking in Java上的说法,super表示下界,而extends表示上界,方法二之所以没有办法通过,是因为被放到List里面去的可能是A,也可能是任何A的子类,所以编译器没有办法确保类型安全。而方法三之所以编译失败,则是因为编译器不知道get出来的是B还是B的其他的什么子类,因为set方法四允许在list放入B,也允许在list中放入B的子类,也就没有办法保证类型安全。
上面的这段解释听起来可能有点奇怪,都是因为编译器无法判断要获取或者设置的是A和B本身还是A和B的其他的子类才导致的失败。那么Java为什么不干脆用一个关键字来搞定呢?
如果从下面的角度来解释,就能把这个为什么编译会出错的问题解释的更加的直白和清除,也让人更容易理解,先看下面的代码,还是A和B两个类,B继承自A:
Java代码
1.public class Generic2{
2. public static void main(String[] args){
3. List<? extends A> list1 = new ArrayList<A>();
4. List<? extends A> list2 = new ArrayList<B>();
5. List<? super B> list3 = new ArrayList<B>();
6. List<? super B> list4 = new ArrayList<A>();
7. }
8.}
从上面这段创建List的代码我们就更加容易理解super和extends关键字的含义了。首先要说明的一点是,Java强制在创建对象的时候必须给类型参数制定具体的类型,不能使用通配符,也就是说new ArrayList<? extends A>(),new ArrayList<?>()这种形式的初始化语句是不允许的。
从上面main函数的第一行和第二行,我们可以理解extends的含义,在创建ArrayList的时候,我们可以指定A或者B作为具体的类型,也就是,如果<? extends X>,那么在创建实例的时候,我们就可以用X或者扩展自X的类为泛型参数来作为具体的类型,也可以理解为给?号指定具体类型,这就是extends的含义。
同样的,第三行和第四行就说明,如果<? super X>,那么在创建实例的时候,我们可以指定X或者X的任何的超类来作为泛型参数的具体类型。
当我们使用List<? extends X>这种形式的时候,调用List的add方法会导致编译失败,因为我们在创建具体实例的时候,可能是使用了X也可能使用了X的子类,而这个信息编译器是没有办法知道的,同时,对于ArrayList<T>来说,只能放一种类型的对象。这就是问题的本质。而对于get方法来说,由于我们是通过X或者X的子类来创建实例的,而用超类来引用子类在Java中试合法的,所以,通过get方法能够拿到一个X类型的引用,当然这个引用可以指向X也可以指向X的任何子类。
而当我们使用List<? super X>这种形式的时候,调用List的get方法会失败。因为我们在创建实例的时候,可能用了X也可能是X的某一个超类,那么当调用get的时候,编译器是无法准确知晓的。而调用add方法正好相反,由于我们使用X或者X的超类来创建的实例,那么向这个List中加入X或者X的子类肯定是没有问题的,因为超类的引用是可以指向子类的。
最后还有一点,这两个关键字的出现都是因为Java中的泛型没有协变特性的倒置的。
AJPFX详解泛型中super和extends关键字的更多相关文章
- 详解Objective-C中委托和协议
Objective-C委托和协议本没有任何关系,协议如前所述,就是起到C++中纯虚类的作用,对于“委托”则和协议没有关系,只是我们经常利用协议还实现委托的机制,其实不用协议也完全可以实现委托. AD: ...
- 详解Java中的clone方法
详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...
- jQuery:详解jQuery中的事件(二)
上一篇讲到jQuery中的事件,深入学习了加载DOM和事件绑定的相关知识,这篇主要深入讨论jQuery事件中的合成事件.事件冒泡和事件移除等内容. 接上篇jQuery:详解jQuery中的事件(一) ...
- 图文详解Unity3D中Material的Tiling和Offset是怎么回事
图文详解Unity3D中Material的Tiling和Offset是怎么回事 Tiling和Offset概述 Tiling表示UV坐标的缩放倍数,Offset表示UV坐标的起始位置. 这样说当然是隔 ...
- 【转】详解C#中的反射
原帖链接点这里:详解C#中的反射 反射(Reflection) 2008年01月02日 星期三 11:21 两个现实中的例子: 1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内 ...
- 详解Webwork中Action 调用的方法
详解Webwork中Action 调用的方法 从三方面介绍webwork action调用相关知识: 1.Webwork 获取和包装 web 参数 2.这部分框架类关系 3.DefaultAction ...
- 【转】详解JavaScript中的this
ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...
- 深入详解SQL中的Null
深入详解SQL中的Null NULL 在计算机和编程世界中表示的是未知,不确定.虽然中文翻译为 “空”, 但此空(null)非彼空(empty). Null表示的是一种未知状态,未来状态,比如小明兜里 ...
- java 乱码详解_jsp中pageEncoding、charset=UTF -8"、request.setCharacterEncoding("UTF-8")
http://blog.csdn.net/qinysong/article/details/1179480 java 乱码详解__jsp中pageEncoding.charset=UTF -8&quo ...
随机推荐
- 利用shuf对数据记录进行随机采样
最近在用SVM为分类器做实验,但是发现数据量太大(2000k条记录)但是训练时间过长...让我足足等了1天的啊!有人指导说可以先进行一下随机采样,再训练,这样对训练结果不会有太大影响(这个待考证).所 ...
- OutputStream和InputStream的区别 + 实现java序列化
我们所说的流,都是针对内存说的,比如为什么打印到屏幕上就是System.out.println();而从屏幕等待用户输入的却是System.in呢?因为对于内存来说,把字符串打印到屏幕上是从内存流向屏 ...
- 如何在Android studio中同时打开多个工程?
最近学习Android Studio,想同时打开两个Project.但是点击File->Open之后,原有的Project被关闭掉了.怎么在新的窗口中打开Project呢? 解决: 点击Help ...
- 超线程技术——超线程技术让(P4)处理器增加5%的裸晶面积,就可以换来15%~30%的效能提升,本质单核模拟双核!和异步编程的思想无异。
超线程是Intel 所研发的一种技术,于2002年发布.超线程的英文是HT技术,全名为Hyper-Threading,中文又名超线程.超线程技术原先只应用于Intel Xeon处理器中,当时称为Sup ...
- URAL2104. Game with a Strip(博弈)
There is a strip 1 × n with two sides. Each square of the strip (their total amount is 2n, n squares ...
- Watir: 很久以前,对Watir开始学习时候做的笔记
1). buttons Xpath 1)Button properties browser.button(:xpath,"//input[@id='b2']/").name bro ...
- 前端之html第一天
一.内容
- vim带你装逼带你飞(二)
上篇我贴上了我使用的vim配置及插件配置,有这些东西只能是一个脚本堆积,无从谈高效的代码阅读开发. 下面我们就来写经常使用的命令,就从配置F系列快捷键开始吧. F+ n 快捷键配置 F1基本上时帮助, ...
- bzoj 1927 [Sdoi2010]星际竞速【最小费用最大流】
果然还是不会建图- 设\( i \)到\( j \)有通路,代价为\( w[i][j] \),瞬移到i代价为\( a[i] \),瞬移到i代价为\( a[j] \),逗号前是流量. 因为每个点只能经过 ...
- bzoj 2876: [Noi2012]骑行川藏【拉格朗日乘数法+二分】
详见: http://blog.csdn.net/popoqqq/article/details/42366599 http://blog.csdn.net/whzzt/article/details ...