面向问题编程——Java泛型
2015-08-17 21:07
162 查看
Java中的泛型历来烧脑,从Object到上界下界修罗界,各种神奇的编译错误让泛型编程痛苦不堪。在这篇里,我总结一下泛型声明方式。
这样的方法确实极为简单。可是问题是显然的,参数o的类型无法保障,随时传进来一个鬼东西,触发异常。
这样,我们就能解决比较对象不一致的问题了。可是这就解决了所有问题了吗?
一个自然地想法是使用Classed来声明成员变量。
然而这会滋生一个问题,比如一个无产阶级的党派可以设置资本家作为领袖,这种Naive的事情不能发生。而现在的泛型方式,虽然能够保证类型的一致,但是不能保证这个类型是Classed子类。
直接通过父类声明,可以解决继承的限制;通过泛型,可以解决类型的一致性问题。它们结合起来呢?
Java用
针对刚才的问题,我们写如下的代码 :
通过描述T和Classed关系,保证了任何T都是Classed的子类,并且leader一定是类型T的,这样就解决了对类型限制和一致性的问题。
任何游戏都基于CF,而基于CF的游戏,他们的粉(nao)丝(can)喜欢撕逼。也就是说,它们是Sibiable的。
当然,能撕逼的不仅仅有游戏,还有动漫。任何动漫都是来源于《喜羊羊(HappyShit)》的,所有的动漫,也都可以撕逼。
如果我们需要编写一个列表,来记录下所有可以撕逼的东西怎么办呢?利用刚才上界,我们可以写出这样的代码。
然而这并不满足我们的需求。我们脑洞大开一下,使用一个嵌套的约束呢?
我们很容易发现,这样做除了Cf、HappyShit两个基类外,他们任何的子类都不能添加进去!因为他们子类实现的是Sibiable<Cf>接口或者Sibiable<HappyShit>,而类的要求是必须要实现自身作为参数的Sibiable接口。
如果一个类Self实现了Sibiable<Self>,那么它的子类都实现了这个接口。Self这个类,与它的子类是超类与子类的关系,也就是
这里的?就是对一个泛型的使用。从内向外理解一下就是:
首先要一个类它是T的超类,这个类作为Sibiable的参数类型。而T是这个Sibiable的子类。说人话就是:T的父类实现了Sibiable<自身>的接口。
最原始的泛型方式——抄袭Object!
Java中,一切对象基于Object。所以,当没有泛型可用的远古时代,一切泛型,都通过Object来实现。首先让我们设计一个与相同类型的对象对比的接口。// 使用Object作为基类完成泛型 interface Cmp_0 { int compareTo(Object o); }
这样的方法确实极为简单。可是问题是显然的,参数o的类型无法保障,随时传进来一个鬼东西,触发异常。
简单泛型——TTT
为了解决上述的问题,不妨把C++的泛型语法借鉴过来,一个T简明易懂。// 最简单的泛型方式 interface Cmp_1<T> { int compareTo(T o); }
这样,我们就能解决比较对象不一致的问题了。可是这就解决了所有问题了吗?
类型限制+一致性——extends
参见下面的场景:我想声明一个只能储存Classed及其子类型的类Party,并且所有Classed类型的对象都是同一种子类型的。说人话就是:同一阶级的人组成党派。一个自然地想法是使用Classed来声明成员变量。
class Party_0 { // 领袖 private Classed leader; // getters, settters }
然而这会滋生一个问题,比如一个无产阶级的党派可以设置资本家作为领袖,这种Naive的事情不能发生。而现在的泛型方式,虽然能够保证类型的一致,但是不能保证这个类型是Classed子类。
class Party_1<T> { // 领袖 private T leader; // getters, setters }
直接通过父类声明,可以解决继承的限制;通过泛型,可以解决类型的一致性问题。它们结合起来呢?
Java用
extends关键字来的表明两个类的继承关系,这里Java讲这种关系延伸到了泛型之中。因为泛型类基于
extends后面的类,所以称这种声明为上界。
针对刚才的问题,我们写如下的代码 :
// T必须是Classed或者其子类 class Party_2<T extends Classed> { private T leader; }
通过描述T和Classed关系,保证了任何T都是Classed的子类,并且leader一定是类型T的,这样就解决了对类型限制和一致性的问题。
下界为子而生——super
然而只有上界还是不够的。让我们来看这样一个问题。任何游戏都基于CF,而基于CF的游戏,他们的粉(nao)丝(can)喜欢撕逼。也就是说,它们是Sibiable的。
// 可撕逼的 interface Sibiable<T> { // 对啦,撕逼能有什么结果呢?笑了 void sibi(T sb); } // 游戏起源CF class Cf implements Sibiable<Cf> { } // DNF以F结尾,抄袭CF class DNF extends Cf { }
当然,能撕逼的不仅仅有游戏,还有动漫。任何动漫都是来源于《喜羊羊(HappyShit)》的,所有的动漫,也都可以撕逼。
// 动漫屎祖喜羊羊 class HappyShit implements Sibiable<HappyShit> { } // 黄段子当然也抄袭了喜羊羊 class YellowSegments extends HappyShit { }
如果我们需要编写一个列表,来记录下所有可以撕逼的东西怎么办呢?利用刚才上界,我们可以写出这样的代码。
class SibiList_0<T extends HappyShit> { } class SibiList_1<T extends Cf> { }
然而这并不满足我们的需求。我们脑洞大开一下,使用一个嵌套的约束呢?
class SibiList_2<T extends Sibiable<T>> { }
我们很容易发现,这样做除了Cf、HappyShit两个基类外,他们任何的子类都不能添加进去!因为他们子类实现的是Sibiable<Cf>接口或者Sibiable<HappyShit>,而类的要求是必须要实现自身作为参数的Sibiable接口。
如果一个类Self实现了Sibiable<Self>,那么它的子类都实现了这个接口。Self这个类,与它的子类是超类与子类的关系,也就是
super。那么将这种关系推广到泛型之中不就好了嘛?于是我们有了这样的代码:
class SibiList_3<T extends Sibiable<? super T>> { }
这里的?就是对一个泛型的使用。从内向外理解一下就是:
首先要一个类它是T的超类,这个类作为Sibiable的参数类型。而T是这个Sibiable的子类。说人话就是:T的父类实现了Sibiable<自身>的接口。
总结
Java的泛型机制从最原始的Object到最终的上下界限制,不断优化迭代,使用更复杂的语法,使之更符合需求。相关文章推荐
- Eclipse初体验
- java双缓冲 笔记
- Spring学习笔记-springMVC基于注解的控制器(Demo)
- 谈谈Java中的集合
- Java学习笔记(十二):泛型的使用
- 关于java的设计目标
- Java线程:线程状态的转换
- Java陷阱之assert关键字
- java如何正确停止一个线程
- 一致性哈希算法学习及JAVA代码实现分析
- java中split以"."分割
- Java Prim算法
- MyEclipse 快捷键
- [JavaWeb基础] 011.Struts2 配置拦截器
- HashMap和HashSet的区别
- Java解析XML
- java环境配置
- eclipse-hadoop插件
- java枚举基础及使用
- Java反射破坏单例模式