《Java泛型.ppt》由会员分享,可在线阅读,更多相关《Java泛型.ppt(39页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、泛型泛型(Generics)Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.本章目录q强类型集合类q泛型类q泛型通配符q泛型方法q继承中的泛型q泛型接口和枚举q类型去除Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.集合类中的数据类型集合类中可以存储各种数据,数据一旦存入,其类型均会转化为Object类型。从集合类中取出数据时,一般均需要将Object类型转换回存入之前的实际类型 Vector v=new Vector();v.
2、add(张三);/存入字符串 String name=(String)v.get(0);/强制类型转换,OK v.add(new Date();/存入当前时间对象,OK /*由于Date类型不能转换为String,下面语句会在运行时发生错误,但这种错误在编译时不会被检查出来 */String date=(String)v.get(1);/编译器不会发现这里有问题Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.强类型集合传统的集合类的实例中可以存储任意类型数据,这种集合类称为弱类型集合类。JDK1.5以后,引入了
3、强类型集合类强类型集合类中,只能存储指定类型的数据在强类型集合类中取出数据时,无需进行类型转换处理,如果数据类型不配备,编译时会直接报错强类型集合并没有引入新的类名,只需在定义原有集合对象时,用尖括号()指明其存储的数据类型名称即可。Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.强类型集合示例/下面的向量类的实例中只能存储字符串类型数据Vector v=new Vector();v.add(张三);/加入的是字符串,OKString name=v.get(0);/取出时,无需做类型转换/*如果想在这种强类型集
4、合中加入日期数据,在编译时就会报告错误*/v.add(new Date();/编译器会直接报告类型不匹配错误Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.定义泛型(Generics)类强类型集合采用了JDK1.5引入的泛型语法。泛型相当于类中一种特殊的类型,这种类型的特点是在实例化该类时可指定为某个具体的实际类型。声明包含泛型的类的格式如下:访问修饰符 class/interface 类名 泛型1 泛型成员1;泛型2 泛型成员2;/.声明中的泛型1、泛型2等等泛型符号可以是任意合法的Java标识符。Confi
5、dential 2013 iSoftStone Holdings Limited.All Rights Reserved.泛型类的声明示例/*此处声明了一个包含泛型T的泛型类,T代表所有可能的类型,而T 的实际类型在Generic类实例化时指定。*/public class Generic private T f;/f为泛型成员 public void setF(T f)/setF方法的参数类型为泛型T this.f=f;public T getF()/getF方法的返回类型为泛型T return f;Confidential 2013 iSoftStone Holdings Limited.
6、All Rights Reserved./f1中的泛型T在此指定为Boolean类型Generic f1=new Generic();/f2中的泛型T在此指定为Integer类型Generic f2=new Generic();/f1的setF方法只能接受Boolean类型数据f1.setF(new Boolean(true);Boolean b=f1.getF();System.out.println(b);/f2的setF方法只能接受Integer类型的数据 f2.setF(new Integer(10);Integer i=f2.getF();System.out.println(i);
7、泛型类的实例化创建泛型类的实例时,可以使用一对尖括号指定泛型的真正类型Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.泛型类实例化时,并不一定要指明泛型对应的实际类型,此时会使用Object作为泛型的默认类型编译时编译器会发出警告:Generic f3=new Generic();f3.setF(new Boolean(false);Note:Generic.java uses unchecked or unsafe operations.Note:Recompile with-Xlint:unchecked
8、for details.实例化时的泛型的默认类型Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.建立类型为泛型类的数组如果要建立泛型类的数组,需要注意new关键字后面不要加入泛型的实际类型名,如下所示:Generic gs;/声明泛型类的数组/先对泛型数组进行初始化gs=new Generic5;/不要写成new Generic5/再分别为每一个数组元素进行初始化gs0=new Generic();/为第一个数组元素赋值/.Confidential 2013 iSoftStone Holdings Limite
9、d.All Rights Reserved.public class Generic2 private T1 f1;private T2 f2;/./给出泛型T1,T2的实际类型Generic f=new Generic();/没有给出T1,T2的实际类型Generic f1=new Generic();/T1,T2将被默认为是Object类型包含多个泛型的类定义示例包含有两个泛型定义的类声明和实例化:Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.public class Generic3 private T
10、 array;/此处不能用new T实例化array public void setArray(T array)this.array=array;public T getArray()return array;泛型成员的使用在泛型类中的泛型成员不能直接实例化,其实例必须要通过方法的参数传递给泛型成员:Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.泛型成员实例化示例通过方法的泛型参数,将数组的实例传递给类中的泛型数组:String strs=caterpillar,momor,bush;Generic3 f=n
11、ew Generic3();/向泛型成员array传递实际的字符串数组f.setArray(strs);/读取泛型成员array的值,将其赋给字符串数组变量strsstrs=f.getArray();/此时array的类型为字符串数组Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.泛型成员的可用方法由于泛型类型只有在类实例化后才能确定,类中的泛型成员只能使用Object类型中的方法:class Generic T f;void setF(T f)this.f=f;/.void doSome()/*getClas
12、s和toString都是Object中的方法 */System.out.println(f.getClass().getName();System.out.println(f.toString();Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.extends关键字用来指定泛型的上限,在实例化泛型类时,为该泛型指定的实际类型必须是指定指定的实际类型必须是指定类的子类或指定接口的子接口类的子类或指定接口的子接口在限定泛型的类型时,无论要限定的是接口或是类,都要使用extends关键词import java.uti
13、l.List;public class ListGeneric private T list;public void setList(T list)this.list=list;public T getList()return list;限制泛型上限类型Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.ListGeneric f1=new ListGeneric();ListGeneric f2=new ListGeneric();限制泛型上限类型的示例/如果不是List的类型,编译时就会发生错误ListGene
14、ric f3=new ListGeneric();type parameter java.util.HashMap is not within its boundListGeneric f3=new ListGeneric();Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.public class Generic /.public class Generic /.默认的泛型限制类型定义泛型类别时,如果只写以下代码:相当于下面的定义方式Confidential 2013 iSoftStone Holdings
15、Limited.All Rights Reserved.限定泛型上限后的成员可用方法泛型类型的上限一经限定,类中的泛型成员就可使用上限类型中的方法和其他可用成员:import java.util.List;import static java.lang.System.out;/静态导入public class ListGeneric private T list;public void setList(T list)this.list=list;public void doSome()/add、get方法都是List接口中定义的方法 list.add(new Integer(0);out.pr
16、intln(list.get(0);/此处省略了System Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.Generic f1=new Generic();Generic f2=new Generic();f1=f2;/发生编译错误 incompatible typesfound:Genericrequired:Genericf1=f2;泛型类实例之间的赋值同一泛型类,如果实例化时给定的实际类型不同,则这些实例的类型是不兼容的,不能相互赋值。Confidential 2013 iSoftStone Hold
17、ings Limited.All Rights Reserved.泛型中的Object类型兼容性Object是所有类的父类,因此,所有的类型的实例都可赋值给声明为Object类型的变量在实例化泛型类时,将泛型指定为Object类型却不存在着和其他类型之间的兼容性:Generic f1=new Generic();Generic f2=new Generic();Generic f=f1;/f1和f类型并不兼容,发生编译错误f=f2;/f2和f类型同样不兼容,也会发生编译错误 Boolean f1=new Boolean(true);Integer f2=new Integer(1);Objec
18、t f=f1;/OKf=f2;/OK Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.泛型通配字符(Wildcard)泛型类实例之间的不兼容性会带来使用的不便。使用泛型通配符(?)声明泛型类的变量可以解决这个问题Generic f1=new Generic();Generic f2=new Generic();Generic f3=new Generic();/f可代表Generic所有可能的实例Generic f;f=f1;/OKf=f2;/OKf=f3;/OKConfidential 2013 iSoftS
19、tone Holdings Limited.All Rights Reserved.通配符用作方法的参数class Util /Collection可以匹配任何强类型集合 static void printCollection(Collection c)for(Object o:c)System.out.println(o);通配符也可以用于方法的参数类型的声明,表示该参数可接受对应泛型类型的任意实例。以下类定义中的printCollection方法可以打印任意强类型集合中的内容Confidential 2013 iSoftStone Holdings Limited.All Rights R
20、eserved.Generic f=null;f=new Generic();/Ok.f=new Generic();/OK./以下语句会发生编译错误,因为HashMap没有实现List接口f=new Genric();为通配符指定匹配上限和限制泛型的上限相似,同样可以使用extends关键字限定通配符匹配类型的上限:incompatible typesfound:Genericrequired:Genericf=new Generic();Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved./将f限定为只能代表采
21、用java.sql.Date的父类实例化的实例Generic f=null;f=new Generic();/Ok/Ok,java.util.Date是java.sql.Date的父类f=new Generic();/错误,因为String不是java.sql.Date的父类f=new Generic();限定通配符匹配类型的下限还可以使用super关键词将通配符匹配类型限定为某个类型及其父类型Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.Generic f=new Generic();foo.setF(ca
22、terpillar);Generic immutableF=f;/可读取泛型成员f中保存的字符串实例System.out.println(immutableF.getF();/可通过传递null参数来移除泛型成员f中保存的字符串实例immutableF.setF(null);/不能通过immutableF的setF方法再次传递新的实例给类中/泛型成员f,所以下面这行无法通过编译immutableF.setF(wang);通配符对泛型成员的影响一旦对象使用通配字符声明,就无法利用它为类中的泛型成员传入新的实例,这时只能读取其中的泛型成员或者移除泛型成员存储的原有实例。Confidential 2
23、013 iSoftStone Holdings Limited.All Rights Reserved.泛型默认类型的实例类型兼容性实例化泛型类时采用默认泛型类型,此时泛型类的实例和其他给定类型的泛型类实例之间存在着类型兼容性,可以直接相互赋值。使用泛型默认类型虽然可以做到类型的兼容性,但会失去泛型带来的编译时刻类型检查的优点。Generic f1=new Generic();Generic f2=new Generic();Generic f=new Generic();/默认泛型类型f =f1;/OKf =f2;/OKf1=f;/OKf2=f;/OK Confidential 2013 i
24、SoftStone Holdings Limited.All Rights Reserved.通配符用作方法参数的局限性考虑如下任务:编写一个方法,该方法含有两个参数,一个参数类型为Object类型的数组,另一个参数类型为对应的强类型集合,需要将数组中的元素复制到集合中。考虑到通配符的作用,在类M中有如下的方法定义:class M/*aToC方法的参数c因为是用通配符表示的任意强类型的集合,而?代表未知类型,编译器无法确定其具体的类型,所以会导致错误*/public static void aToC(Object a,Collection c)for(Object o:a)c.add(o);/
25、编译出错,此处可以用泛型方法解决 Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.泛型方法不仅类可以声明泛型,类中的方法也可以声明仅用于自身的泛型,这种方法叫做泛型方法。其定义格式为:访问修饰符 返回类型 方法名(参数列表)实现代码 其中泛型列表为用逗号分隔的合法Java标识符。在泛型列表中声明的泛型,可用于该方法的返回类型声明、参数类型声明和方法代码中的局部变量的类型声明。类中其他方法不能使用当前方法声明的泛型。Confidential 2013 iSoftStone Holdings Limited.All
26、 Rights Reserved.泛型方法声明示例使用泛型方法可以解决上述的泛型通配符造成的问题:class M/*方法aToC声明了一个泛型T,该方法将任意类型的数组a中的所有 元素复制到相应的强类型集合c当中而不会导致编译错误。此处的泛型声明T仅作用于aToC方法的声明部分和实现代码部分。*/public static void aToC(T a,Collection c)for(T o:a)c.add(o);/不会出现类似通配符的编译错误 Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved./对M中定义的泛型
27、方法aToC进行调用测试class TestM public static void main(String args)String sa=new String100;Collection cs=new Vector();Collection co=new Vector();M.aToC(sa,cs);/aToC中的泛型T此时匹配类型String M.aToC(sa,co);/aToC中的泛型T此时匹配类型Object 泛型方法的调用调用泛型方法和调用普通方法没有任何不同,只需要传递含有具体类型的实参即可:Confidential 2013 iSoftStone Holdings Limite
28、d.All Rights Reserved.限定泛型方法中泛型类型泛型方法中的声明的泛型,同样可以使用extends关键字限定其类型的下限:class M /限定aToC方法中的泛型T必须是实现了序列化接口的类型 public static void aToC(T a,Collection c)for(T o:a)c.add(o);Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.public class SubGeneric extends Generic private T3 f3;public void s
29、etF3(T3 f3)this.f3=f3;public T3 getF3()return f3;继承中的泛型继承时如需保留父类泛型,需要在声明时加入父类泛型如果不保留父类中的泛型声明,则继承下来的T1与T2自动变为Object类型建议父类中的泛型声明在子类中都要保留Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.继承时指定父类的泛型类型如果在继承时,不想保留父类中的泛型,但也不想使用默认的Object类型,此时可以直接指定父类中的泛型。public class SubGeneric extends Gener
30、ic private T3 f3;public void setF3(T3 f3)this.f3=f3;public T3 getF3()return f3;Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.public class IC implements I public Object getT1()/对接口方法getT1的实现 public Object getT2()/对接口方法getT2的实现 /.泛型接口接口也可包含泛型的声明:实现泛型接口时,类在定义时可以不声明泛型接口中的泛型,此时接口中的泛型也
31、会自动变为Object类型:public interface I T1 getT1();T2 getT2();/.Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.public class IC implements I public T1 getT1()/对接口方法getT1的实现 public T2 getT2()/对接口方法getT2的实现 /./声明泛型接口的变量,并利用泛型实现类进行实例化I i=new IC();泛型接口的实现如果需要在实现泛型接口时,保留接口中的泛型,类在定义时就必须要保留泛型接口中
32、的泛型声明:Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved./实现接口I时,直接指定泛型T1、T2的类型 class IC implements I /由于指定接口I中T1类型为String,getT1返回类型必须为String public String getT1()/由于指定接口I中T2类型为Integer,getT2返回类型必须为Integer public Integer getT2()/.实现泛型接口时指定泛型类型在实现泛型接口时,也可直接指定接口中的泛型的实际类型:Confidential 201
33、3 iSoftStone Holdings Limited.All Rights Reserved.泛型和枚举由于枚举类型不能直接实例化,所以枚举的定义中不能含有泛型的声明,但枚举中可包含泛型方法的定义。public enum TrafficLight Red,Amber,Green;private int duration;public static void avgDuration(Collection carType)/./.Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.类型去除(Type Erasur
34、e)JDK1.5引入的泛型实际上是一种编译器层次上的语法糖,在虚拟机层次上并不直接支持泛型。编译器在编译时会自动去除有关泛型的定义,这样的处理方式有以下特点:字节码与1.5以前的版本相同,保持了字节码的兼容性安全性不受影响性能不受影响-没增加也没减少泛型的实际类型信息保存在类文件里Confidential 2013 iSoftStone Holdings Limited.All Rights Reserved.类型去除影响的一些Java语法由于JDK1.5采用类型去除处理泛型语法,造成了一些比较晦涩的Java语法变化:instanceof运算符不能用于包含泛型类型的判断 if(a instanceof java.util.List)/错误方法的重载出现了一些怪异的语法现象,一些看似合理的方法重载不能通过编译,这些有望在JDK1.7中得到解决:/print方法1 void print(java.util.List list);/print方法2,不能和方法1同时存在 void print(java.util.List list);/print方法3,可以和方法1同时存在,构成重载方法 int print(java.util.List list);