miaoshuncai

来源:互联网 发布:手机望远镜软件 推荐 编辑:程序博客网 时间:2024/06/05 04:45

编辑本段介绍

在java se 1.5之前,没有泛型的情况的下,通过对类型object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

编辑本段规则和限制

1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。3、泛型的类型参数可以有多个。4、泛型的参数类型可以使用extends语句,例如。习惯上称为“有界类型”。5、泛型的参数类型还可以是通配符类型。例如class classtype = class.forname("java.lang.string");泛型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。在此给出我曾经 了解泛型时候写出的两个例子(根据看的印象写的),实现同样的功能,一个使用了泛型,一个没有使用,通过对比,可以很快学会泛型的应用,学会这个基本上学 会了泛型70%的内容。例子一:使用了泛型class gen {private t ob; //定义泛型成员变量public gen(t ob) {this.ob = ob;}public t getob() {return ob;}public void setob(t ob) {this.ob = ob;}public void showtype() {system.out.println("t的实际类型是: " + ob.getclass().getname());}}public class gendemo {public static void main(string[] args){//定义泛型类gen的一个integer版本gen intob=new gen(88);intob.showtype();int i= intob.getob();system.out.println("value= " + i);system.out.println("----------------------------------");//定义泛型类gen的一个string版本gen strob=new gen("hello gen!");strob.showtype();string s=strob.getob();system.out.println("value= " + s);}}例子二:没有使用泛型public class gen2 {private object ob; //定义一个通用类型成员public gen2(object ob) {this.ob = ob;}public object getob() {return ob;}public void setob(object ob) {this.ob = ob;}public void showtyep() {system.out.println("t的实际类型是: " + ob.getclass().getname());}}public class gendemo2 {public static void main(string[] args) {//定义类gen2的一个integer版本gen2 intob = new gen2(new integer(88));intob.showtyep();int i = (integer) intob.getob();system.out.println("value= " + i);system.out.println("---------------------------------");//定义类gen2的一个string版本gen2 strob = new gen2("hello gen!");strob.showtyep();string s = (string) strob.getob();system.out.println("value= " + s);}}运行结果:两个例子运行demo结果是相同的,控制台输出结果如下:t的实际类型是:java.lang.integervalue= 88----------------------------------t的实际类型是: java.lang.stringvalue= hello gen!process finished with exit code 0看明白这个,以后基本的泛型应用和代码阅读就不成问题了。

编辑本段逐渐深入泛型

1、没有任何重构的原始代码

有两个类如下,要构造两个类的对象,并打印出各自的成员x。public class stringfoo {private string x;public stringfoo(string x) {this.x = x;}public string getx() {return x;}public void setx(string x) {this.x = x;}}public class doublefoo {private double x;public doublefoo(double x) {this.x = x;}public double getx() {return x;}public void setx(double x) {this.x = x;}}以上的代码实在无聊,就不写如何实现了。

2、对上面的两个类进行重构,写成一个类

因为上面的类中,成员和方法的逻辑都一样,就是类型不一样,因此考虑重构。object是所有类的父类,因此可以考虑用object做为成员类型,这样就可以实现通用了,实际上就是“object泛型”,暂时这么称呼。public class objectfoo {private object x;public objectfoo(object x) {this.x = x;}public object getx() {return x;}public void setx(object x) {this.x = x;}}写出demo方法如下:public class objectfoodemo {public static void main(string args[]) {objectfoo strfoo = new objectfoo(new stringfoo("hello generics!"));objectfoo doufoo = new objectfoo(new doublefoo(double("33")));objectfoo objfoo = new objectfoo(new object());system.out.println("strfoo.getx="+(stringfoo)strfoo.getx());system.out.println("doufoo.getx="+(doublefoo)doufoo.getx());system.out.println("objfoo.getx="+objfoo.getx());}}运行结果如下:strfoo.getx=hello generics!doufoo.getx=33.0objfoo.getx=java.lang.object@19821f解说:在java 5之前,为了让类有通用性,往往将参数类型、返回类型设置为object类型,当获取这些返回类型来使用时候,必须将其“强制”转换为原有的类型或者接口,然后才可以调用对象上的方法。

3、java1.5泛型来实现

强制类型转换很麻烦,我还要事先知道各个object具体类型是什么,才能做出正确转换。否则,要是转换的类型不对,比如将“hello generics!”字符串强制转换为double,那么编译的时候不会报错,可是运行的时候就挂了。那有没有不强制转换的办法----有,改用 java5泛型来实现。public class genericsfoo {private t x;public genericsfoo(t x) {this.x = x;}public t getx() {return x;}public void setx(t x) {this.x = x;}}public class genericsfoodemo {public static void main(string args[]){genericsfoo strfoo=new genericsfoo("hello generics!");genericsfoo doufoo=new genericsfoo(new double("33"));genericsfoo objfoo=new genericsfoo(new object());system.out.println("strfoo.getx="+strfoo.getx());system.out.println("doufoo.getx="+doufoo.getx());system.out.println("objfoo.getx="+objfoo.getx());}}运行结果:strfoo.getx=hello generics!doufoo.getx=33.0objfoo.getx=java.lang.object@19821f和使用“object泛型”方式实现结果的完全一样,但是这个demo简单多了,里面没有强制类型转换信息。下面解释一下上面泛型类的语法:使用来声明一个类型持有者名称,然后就可以把t当作一个类型代表来声明成员、参数和返回值类型。当然t仅仅是个名字,这个名字可以自行定义。class genericsfoo 声明了一个泛型类,这个t没有任何限制,实际上相当于object类型,实际上相当于 class genericsfoo。与object泛型类相比,使用泛型所定义的类在声明和构造实例的时候,可以使用“”来一并指定泛型类型持有者的真实类型。类如genericsfoo doufoo=new genericsfoo(new double("33"));当然,也可以在构造对象的时候不使用尖括号指定泛型类型的真实类型,但是你在使用该对象的时候,就需要强制转换了。比如:genericsfoo doufoo=new genericsfoo(new double("33"));实际上,当构造对象时不指定类型信息的时候,默认会使用object类型,这也是要强制转换的原因。

编辑本段泛型的高级应用

1、限制泛型的可用类型

在上面的例子中,由于没有限制class genericsfoo类型持有者t的范围,实际上这里的限定类型相当于object,这和“object泛型”实质是一样的。限制比如我们要限制t为集合接口类型。只需要这么做:class genericsfoo,这样类中的泛型t只能是collection接口的实现类,传入非collection接口编译会出错。注意:这里的限定使用关键字 extends,后面可以是类也可以是接口。但这里的extends已经不是继承的含义了,应该理解为t类型是实现collection接口的类型,或者t是继承了xx类的类型。下面继续对上面的例子改进,我只要实现了集合接口的类型:public class collectiongenfoo {private t x;public collectiongenfoo(t x) {this.x = x;}public t getx() {return x;}public void setx(t x) {this.x = x;}}实例化的时候可以这么写:public class collectiongenfoodemo {public static void main(string args[]) {collectiongenfoo listfoo = null;listfoo = new collectiongenfoo(new arraylist());//出错了,不让这么干。// collectiongenfoo listfoo = null;// listfoo=new collectiongenfoo(new arraylist());system.out.println("实例化成功!");}}当前看到的这个写法是可以编译通过,并运行成功。可是注释掉的两行加上就出错了,因 为这么定义类型的时候,就限定了构造此类实例的时候t是确定的一个类型,这个类型实现了collection接口,但是实现 collection接口的类很多很多,如果针对每一种都要写出具体的子类类型,那也太麻烦了,我干脆还不如用object通用一下。别急,泛型针对这种 情况还有更好的解决方案,那就是“通配符泛型”。

2、通配符泛型

为了解决类型被限制死了不能动态根据实例来确定的缺点,引入了“通配符泛型”,针对上面的例子,使用通配泛型格式为,“?”代表未知类型,这个类型是实现collection接口。那么上面实现的方式可以写为:public class collectiongenfoodemo {public static void main(string args[]) {collectiongenfoo listfoo = null;listfoo = new collectiongenfoo(new arraylist());//现在不会出错了collectiongenfoo listfoo1 = null;listfoo=new collectiongenfoo(new arraylist());system.out.println("实例化成功!");}}注意:1、如果只指定了,而没有extends,则默认是允许object及其下的任何java类了。也就是任意类。2、通配符泛型不单可以向下限制,如,还可以向上限制,如,表示类型只能接受double及其上层父类类型,如number、object类型的实例。3、泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口,泛型方法。这些都泛型类中泛型的使用规则类似。

编辑本段泛型方法

是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。如:public class examplea {publicvoid f(t x) {system.out.println(x.getclass().getname());}public static void main(string[] args) {examplea ea = new examplea();ea.f(" ");ea.f(10);ea.f('a');ea.f(ea);}}输出结果:java.lang.stringjava.lang.integerjava.lang.characterexamplea使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。需要注意,一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
原创粉丝点击