编程专题讲座-java开发技术第10型_第1页
编程专题讲座-java开发技术第10型_第2页
编程专题讲座-java开发技术第10型_第3页
编程专题讲座-java开发技术第10型_第4页
编程专题讲座-java开发技术第10型_第5页
已阅读5页,还剩20页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第10章 泛型是JDK1.5中新加入的元素,它改变了API中的许多类和方法。使用泛型,的强大功能,从根本上改变了Java代码的编写方式。IntegerIntegermax(Integera,Integerb){returna>b?a:b;}IntegerDoubleFloat类型,那么就需要另外再写max()方法。参数有多少种类型,就要写多少个max()方法。但是无论怎么改变参数的类型,实际上max()方法体的代码并不需要改变。如max()ab的数据类型,而等到调用的时候再来确定这两个参数的数据类型,那么只需要编写一个max()就可以了,这将大大在C++中,提供了函数模板和类模板来实现这能。而从JDK1.5开始,也提供了C++的模板很相似,但它们是采用完全不同的技在泛型出现之前,Java的程序员可以采用一种变通的办法:将参数的类型均为ObjectObject类是所有类的父类,所以它可以指向任何类对象,但这样做不能Object与实【10.1//--------------文件名Generic.java,程序10.1---------- publicclassTobobT,现在不能具体确定它的类型,需要到创建对象时才能确定Generic(To){ob=}TgetOb(){return}void}}//--------------文件名demoGeneric.java,程序10.2----------publicpublicclasspublicstaticvoidmain(String 一个Integer类型的Generic变Generic<Integer>//创建一个Integer类型的Generic对iobj=newintk=iobj.getOb(); 一个String类型的Generic变Generic<String>//创建一个Double类型的Generic对sobj=new Strings=sobj.getOb();}}TypeTypeofTis:java.lang.IntegerTypeofT publicclass 其中,TGeneric的实际类型的占位符。因此,在Generic中,每当需要类型参数时,就会用到T。注意,T是被括在“<>”中的。每个被的类型参数,都要放在尖括号中。由于Generic使用了类型参T T只是一个占位符,所以ob的实际类型要由创建对象时的参数传递进来。比如,T的类型是StringobString类型。o){ob=}它的参oT。这o的实际类型,是由创Generic对象时传递ToobT类型,所以无论实际类型是什TTgetOb(){returnob;综合上面的用法,可以看出,T是一个数据类型的说明,它可以用来说明任何实例方注意:类型参数T不能使用在静态Generic 有对T的都会被替换为Integer。所以ob和o都是Integer类型,而且方法getOb()的返回类型也是Integer类型的。Java的编译器并不会创建多个不同版本的Generic类。相反,编译器会删除所有iobjiobj=new所以用new返回的必须是Generic<Integer>类型。无论是省略Integer,还是将其改成iobjiobjnewGeneric<Double>(1.234错Generic(TGeneric(TJava的自动装箱机制(12.3节中介绍)。当然,创建对象也可iobjiobj=newGeneric(newintintk=注意,getObIntegerint变量时,系统会自动拆intintk=后面创建String版本的过程和前面的完全一样,在此不再赘述。类型,而不能使用int或char之类的简单类型。比如不能这样写:GenericGeneric<intobnewGenericint>(100);//错C++模板的一个重要//--------------文件名twoGen.java,程序10.3----------publicclasstwoGen<T,V>{TVtwoGen(To1,Vo2){ob1=o1;ob2=}//显示TV的类voidSystem.out.println("TypeofTis"+ob1.getClass().getName());System.out.println("TypeofVis"+ob2.getClass().getName());getOb1(){returnob1;getOb2(){eturn//--------------文件名simpGen.java,程序10.4----------publicpublicclasspublicstaticvoidargs[]){twoGen<Integer,String>tgObj; tgObj=newtwoGen<Integer,String>(100," intv=tgObj.getOb1();System.out.println("value:"+v);Stringstr=tgObj.getOb2();System.out.println("value:"+str);}TypeTypeofTisjava.lang.IntegerTypeofVisjava.lang.Stringvalue:100 与只有一个类型参数的泛型相比,本例并没有什么难于理解的地方。Java并没有规定 //--------------文件名Stats.java,程序10.5----------Stats<T>{T[]nums;Stats(Tobj){nums=}average(){doublesum=0.0;for(inti=0;i<nums.length;++i)sum+=returnsum/其中,nums[i].doubleValue()Ingeger、Double等数据封装类转换成双精度数后Number类的子类都有这个方法。但问题是,编译器无法预先知道,程序员的意图是只能使用Number类来创Stats对象,因此,编译时会报告找不到doubleValue()classclassclassname<Textends【10.3//--------------文件名Stats.java,程序10.6----------////下面这个泛型的实际类型参数只能是Number或它的子classStats<TextendsNumber>{T[]nums;Stats(T[]obj){nums=}average(){doublesum=0.0;for(inti=0;i<nums.length;sum+=nums[i].doubleValue(); returnsum/nums.length;}//--------------文件名demoBounds.java,程序10.7----------publicpublicclasspublicstaticvoidmain(Stringargs[]){Integerinums[]=Stats<Integer> iobjnewStats<Integer>(inums);Doublednums[]={1.1,2.2,3.3,4.4,5.5};Stats<Double> dobjnewStats<Double>(dnums);//如果像下面这样创建String类型的对象将无法编译通//Stringsnums[]=//Stats sobj=new//System.out.println("平均值}classStats<Textends 注意:这里使用的关键字仍然是extends而非implements。classStats<TextendsComparable& 注意:限界类型用“&”分隔,因为逗号用来分隔类型参数。在多个限界中StatsdoSomething()的方法,这个方法有一个形式参数,也是Stats类型,如下所示:classclassvoiddoSomething(Statsob){}}IntegerIntegerinums[]=Stats<Integer> iobj=newStats<Integer>(inums);Doublednums[]={1.1,2.2,3.3,4.4,5.5};Stats<Double> dobjnewStats<Double>(dnums);dobj.doSomething(iobj);//错误 voiddoSomething(Stats<T> voiddoSomething(Stats<U> 使用Java提供的通配符“?”,它的使用形式如下: voiddoSomething(Stats<?> 【10.4//--------------文件名Stats.java,程序10.8----------classclassStats<TextendsNumber>{T[]nums;Stats(T[]obj){nums=}average(){doublesum=0.0;for(inti=0;i<nums.length;++i)sum+=nums[i].doubleValue();returnsum/}voiddoSomething(Statsob){//这里使用了类型通配符}//--------------文件名demoWildcard.java,程序10.9----------publicclassdemoWildcard{publicpublicclassdemoWildcard{publicstaticvoidmain(Stringargs[]){Integerinums[]Stats<Integer> iobj=newStats<Integer>(inums);Doublednums[]={1.1,2.2,3.3,4.4,5.5};Stats<Double> dobj=newStats<Double>(dnums); } voiddoSomething(Stats<?>ob)//这里使用了类型通配 classStats<Textends Stats<?extendsInteger> Stats<?extendsString> IntegerNumberStringNumber的子类。通配符无法将上界改classStats<?extends 在C++中,除了可以创建模板类,还可以创建模板函数。在Java中也提供了类似的功能: 权限修饰符(包括private、public、protected)、static和final都必须写在类 【10.5//--------------文件名demoGenMethods.java,程序10.10----------publicpublicclass//定义泛型方法,有一个形式参数用类型参数T来定publicstatic<T>voidshowGenMsg(Tob,n){TlocalObobT来}publicstatic<T>voidob){}publicstaticvoidmain(Stringargs[]){Stringstr="parameter";Integerk=newInteger(123);}型方法相互重载(参数的个数不同)T的使用和泛型类中的使用在第一种调用形式中,传入了一个实际类型:<Integer>,它表明类型参数是 public<T>voiddoSomething(){public<T>voiddoSomething(){Tob;}publicclassGeneric<T>{publicpublicclassGeneric<T>{public<U>voidshowGenMsg(Uob){}}publicpublicclassU>{publicvoidshowGenMsg(U}interface接口名<类型参数表 //--------------文件名MinMax.java,程序10.11----------interfaceinterfaceMinMax<TextendsComparable<T>>{Tmin();Tmax();}T//--------------文件名MyClass.java,程序10.12----------classclassMyClass<TextendsComparable<T>>implementsMinMax<T>{T[]vals;MyClass(Tob){vals=}publicTTval=for(inti=1;i<vals.length;++i)if(vals[i].compareTo(val)<0)val=vals[i];returnval;}publicTTval=for(inti=1;i<vals.length;++i)if(vals[i].compareTo(val)>0)val=vals[i];returnval;}}classclassMyClass<TextendsComparable<T>>implements看上去有点奇怪,它的类型参数T必须和要实现的接口中的完全一样。反而是接口MinMax的类型参数T最初是写成有界形式的,现在已经不再需要重写一遍。如果重写classclassMyClass<TextendsComparable<T>>implementsMinMax<TextendsclassclassMyClassimplementsclassclassMyClassimplements这样写是正确的,现在这个类不再是泛型类。编译器会在编译此类时,将类型参数T 代替,而无需等到创建对象时再处理//--------------文件名demoGenIF.java,程序10.13----------publicpublicclasspublicstaticvoidmain(Stringargs[]){Integerinums[]=Characterchs[]={'x','w','z','y','b','o','p'};MyClass<Integer>iob=newMyClass<Integer>(inums);MyClass<Character>cob=newMyClass<Character>(chs);System.out.println("Maxvalueininums:"+iob.max());System.out.println("Minvalueininums:"+iob.min());System.out.println("Maxvalueinchs:"+cob.max());System.out.println("Minvalueinchs:"+cob.min());}MaxMaxvalueininums:85Minvalueininums:12Maxvalueinchs:zMinvalueinchs:和普通类一样,泛型类也是可以继承的,任何一个泛型类都可以作为父类或子类。不过泛型类与非泛型类在继承时的主要区别在于:泛型类的子类必须将泛型父类所需要的类型参数,沿着继承链向上传递。这与构造方法参数必须沿着继承链向上传递的方式类似。以泛型类为父【10.7//--------------文件名superGen.java,程序10.14----------publicpublicclasssuperGen<T定义一个泛型类Tob;publicsuperGen(Tob){this.ob=ob;}superGen(){ob=publicTpublicTgetOb(){return}//--------------文件名derivedGen.java,程序10.15----------publicclassderivedGen<T>extendssuperGen<T>{publicclassderivedGen<T>extendssuperGen<T>{publicderivedGen(Tob){}}publicclassderivedGen<T>extends 这两个类型参数必须用相同的标识符T。这意味着传递给derivedGen的实际类型也会传递给superGen。例如,下面的定义:derivedGen<Integer>number=new IntegerderivedGensuperGen,因此,后者的成员ob也是Integer类型。虽然derivedGen里面并没有使用类型参数T,但由于它要传递类型参数给父类,所以它不能定义成非泛型类。当然,derivedGenT,还可以增加自己需要的类型参数。下面这个程序展示了一个更为复杂的derivedGen类。//--------------文件名derivedGen.java,程序10.16----------publicpublicclassderivedGen<T,U>extendssuperGen<T>{Udob;publicderivedGen(Tob1,Uob2){super(ob1); 数给父类dob=ob2; }publicUgetDob(){return//--------------文件名demoHerit_1.java,程序10.17----------publicpublicclasspublicstaticvoidmain(String//创建子类的对象,它需要传递两个参数,Integer类型给父类,自己使用String类derivedGen<Integer,String>derivedGen<Integer,String>oa=newderivedGen<Integer,String>(100,"Valueis:");}}ValueValueis:以非泛型类为父【10.8//--------------文件名nonGen.java,程序10.18----------}//--------------文件名derivedNonGen.java,程序10.19----------publicpublicclassderivedNonGen<T>extendsnonGen{Tob;publicderivedNonGen(Tob,intn){super(n);this.ob=}publicTgetOb(){return}//--------------文件名demoHerit_2.java,程序10.20----------publicpublicclasspublicstaticvoidmain(StringderivedNonGen<String>oa=newderivedNonGen<String>("Valueis:",}}Valueis: 运行时类型识机制,也可以采用传统的方法。比如,instanceof操作符。JVM中,泛型类的对象总是一个特定的类型,此时,它不再ainstanceof antnefGc 注意:Integer之类确定的类型。实际上在测同样道理,getClass()返回的也是原始类型。若b是Generic<String>类型,下面a.getClass()== //--------------文件名demoRTTI_1.java,程序10.21----------publicpublicclasspublicstaticvoidmain(Stringargs[]){Generic<Integer>iob=newGeneric<Integer>(100);Generic<String>sob=newGeneric<String>("Good");if(iobinstanceofSystem.out.println("Generic<Integer>objectisinstanceofGeneric");if(iobinstanceofGeneric<?>)System.out.println("Generic<Integer>objectisinstanceofif(iob.getClass()==sob.getClass())System.out.println("Generic<Integer>classequalsGeneric<String>}Generic<Integer>objectisinstanceof Generic<Integer>objectisinstanceofGeneric<?>Generic<Integer>Generic<Integer>objectisinstanceofGeneric<?>Generic<Integer>classequalsGeneric<String>class//--------------文件名demoRTTI_2.java,程序10.22----------publicpublicclasspublicstaticvoidmain(StringsuperGen<Integer>oa=newsuperGen<Integer>(100);derivedGen<Integer,String>ob=newderivedGen<Integer,if(oainstanceofSystem.out.println("superGenobjectisinstanceofderivedGen");if(obinstanceofsuperGen)System.out.println("derivedGenobjectisinstanceofsuperGen");if(oa.getClass()==ob.getClass())System.out.println("superGenclassequalsderivedGen}}derivedGenobjectisinstanceof 强制类型 个类:superGen和derivedGen。【10.11//--------------文件名demoForceChange.java,程序10.23----------publicpublicclasspublicstaticvoidmain(StringsuperGen<Integer>oa=newsuperGen<Integer>(100);derivedGen<Integer,String>ob=newderivedGen<Integer,String>if((superGen<Integer>)obinstanceofSystem.out.println("derivedGenSystem.out.println("derivedGenobjectischangedtoif((derivedGen<Integer,String>)oainstanceofderivedGen)System.out.println("superGenobjectischangedtoderivedGen");}}derivedGenderivedGenobjectischangedtoExceptioninthread"main"java.lang.ClassCastException:at提示:建议读者如果不是十分必要,不要做强制类型转换的操作么对应的泛型是否也会具有相同的继承关系呢?比如,Integer是Number的子类,那么Generic<Integer>Generic<Number>的子类呢?答案是:否。比如,下面的代码将不Generic<Number>Generic<Number>oa=newoaGeneric<Integer>的父类,所以这条语句无法编译通过。事实上,10.1Generic类之间没有继承 Jvacas文件的细节。但在使用泛型时,对此过程进行一般的了解是必要的,因为只有了解这一细节,程序员才能理解JavaJDK1.5以前的版本中是没有泛型的,为了保证对以前版本的兼容,Java采用C++的模板完全不同的方式来处理泛型(尽管它们二者的使用看上去很相似),Java【10.12//--------------文件名Gen.java,程序10.24----------////默认情况下,T是由Object限publicclassTob;Gen(Tob){this.ob=getOb(){returnob;}javap CompiledCompiledfrom"Gen.java"publicclassGenjava.lang.Object{java.lang.Objectob; 面将T称为“占位符”的原因。【10.13//--------------文件名GenStr.java,程序10.25----------//T//T是由String限publicclassGenStr<TextendsTob;GenStr(Tob){this.ob=getOb(){returnob;}CompiledCompiledfrom"GenStr.java"publicclassGenStrjava.lang.Object{java.lang.Stringob;java.lang.StringgetOb();}Gen<Integer>Gen<Integer>oa=newGen<Integer>(100);Gen<Integer>ob=oa.getOb();Gen<Integer>ob= 具体指定的参数类型。这一点在10.8.3小节中已经详细介绍过了。也被称为。主要发生在下述三种情况。静态成员共享问//--------------文件名foo.java,程序10

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论