泛型(Generics)强类型集合类泛型类泛型通配符泛型方法继承中的泛型泛型接口和枚举类型去除集合类中的数据类型n集合类中可以存储各种数据,数据一旦存入,其类型均会转化为Object类型。n从集合类中取出数据时,一般均需要将Object类型转换回存入之前的实际类型Vectorv=newVector();v.add(张三);//存入字符串Stringname=(String)v.get(0);//强制类型转换,OKv.add(newDate());//存入当前时间对象,OK/*由于Date类型不能转换为String,下面语句会在运行时发生错误,但这种错误在编译时不会被检查出来*/Stringdate=(String)v.get(1);//编译器不会发现这里有问题强类型集合n传统的集合类的实例中可以存储任意类型数据,这种集合类称为弱类型集合类。nJDK1.5以后,引入了强类型集合类强类型集合类中,只能存储指定类型的数据在强类型集合类中取出数据时,无需进行类型转换处理,如果数据类型不配备,编译时会直接报错强类型集合并没有引入新的类名,只需在定义原有集合对象时,用尖括号()指明其存储的数据类型名称即可。强类型集合示例//下面的向量类的实例中只能存储字符串类型数据VectorStringv=newVectorString();v.add(张三);//加入的是字符串,OKStringname=v.get(0);//取出时,无需做类型转换/*如果想在这种强类型集合中加入日期数据,在编译时就会报告错误*/v.add(newDate());//编译器会直接报告类型不匹配错误定义泛型(Generics)类n强类型集合采用了JDK1.5引入的泛型语法。n泛型相当于类中一种特殊的类型,这种类型的特点是在实例化该类时可指定为某个具体的实际类型。n声明包含泛型的类的格式如下:[访问修饰符]class类名泛型1,泛型2,…{泛型1泛型成员1;泛型2泛型成员2;//....}n声明中的泛型1、泛型2等等泛型符号可以是任意合法的Java标识符。泛型类的声明示例/*此处声明了一个包含泛型T的泛型类,T代表所有可能的类型,而T的实际类型在Generic类实例化时指定。*/publicclassGenericT{privateTf;//f为泛型成员publicvoidsetF(Tf){//setF方法的参数类型为泛型Tthis.f=f;}publicTgetF(){//getF方法的返回类型为泛型Treturnf;}}//f1中的泛型T在此指定为Boolean类型GenericBooleanf1=newGenericBoolean();//f2中的泛型T在此指定为Integer类型GenericIntegerf2=newGenericInteger();//f1的setF方法只能接受Boolean类型数据f1.setF(newBoolean(true));Booleanb=f1.getF();System.out.println(b);//f2的setF方法只能接受Integer类型的数据f2.setF(newInteger(10));Integeri=f2.getF();System.out.println(i);泛型类的实例化n创建泛型类的实例时,可以使用一对尖括号指定泛型的真正类型n泛型类实例化时,并不一定要指明泛型对应的实际类型,此时会使用Object作为泛型的默认类型n编译时编译器会发出警告:Genericf3=newGeneric();f3.setF(newBoolean(false));Note:Generic.javausesuncheckedorunsafeoperations.Note:Recompilewith-Xlint:uncheckedfordetails.实例化时的泛型的默认类型建立类型为泛型类的数组n如果要建立泛型类的数组,需要注意new关键字后面不要加入泛型的实际类型名,如下所示:GenericString[]gs;//声明泛型类的数组//先对泛型数组进行初始化gs=newGeneric[5];//不要写成newGenericString[5]//再分别为每一个数组元素进行初始化gs[0]=newGenericString();//为第一个数组元素赋值//....publicclassGeneric2T1,T2{privateT1f1;privateT2f2;//....}//给出泛型T1,T2的实际类型GenericInteger,Booleanf=newGenericInteger,Boolean();//没有给出T1,T2的实际类型Genericf1=newGeneric();//T1,T2将被默认为是Object类型包含多个泛型的类定义示例n包含有两个泛型定义的类声明和实例化:publicclassGeneric3T{privateT[]array;//此处不能用newT[]实例化arraypublicvoidsetArray(T[]array){this.array=array;}publicT[]getArray(){returnarray;}}泛型成员的使用n在泛型类中的泛型成员不能直接实例化,其实例必须要通过方法的参数传递给泛型成员:泛型成员实例化示例n通过方法的泛型参数,将数组的实例传递给类中的泛型数组:String[]strs={caterpillar,momor,bush};Generic3Stringf=newGeneric3String();//向泛型成员array传递实际的字符串数组f.setArray(strs);//读取泛型成员array的值,将其赋给字符串数组变量strsstrs=f.getArray();//此时array的类型为字符串数组泛型成员的可用方法n由于泛型类型只有在类实例化后才能确定,类中的泛型成员只能使用Object类型中的方法:classGenericT{Tf;voidsetF(Tf){this.f=f;}//....voiddoSome(){/*getClass和toString都是Object中的方法*/System.out.println(f.getClass().getName());System.out.println(f.toString());}}nextends关键字用来指定泛型的上限,在实例化泛型类时,为该泛型指定的实际类型必须是指定类的子类或指定接口的子接口n在限定泛型的类型时,无论要限定的是接口或是类,都要使用extends关键词importjava.util.List;publicclassListGenericTextendsList{privateTlist;publicvoidsetList(Tlist){this.list=list;}publicTgetList(){returnlist;}}限制泛型上限类型ListGenericVectorf1=newListGenericVector();ListGenericArrayListf2=newListGenericArrayList();限制泛型上限类型的示例//如果不是List的类型,编译时就会发生错误ListGenericHashMapf3=newListGenericHashMap();typeparameterjava.util.HashMapisnotwithinitsboundListGenericHashMapf3=newListGenericHashMap();publicclassGenericT{//....}publicclassGenericTextendsObject{//....}默认的泛型限制类型n定义泛型类别时,如果只写以下代码:n相当于下面的定义方式限定泛型上限后的成员可用方法n泛型类型的上限一经限定,类中的泛型成员就可使用上限类型中的方法和其他可用成员:importjava.util.List;importstaticjava.lang.System.out;//静态导入publicclassListGenericTextendsList{privateTlist;publicvoidsetList(Tlist){this.list=list;}publicvoiddoSome(){//add、get方法都是List接口中定义的方法list.add(newInteger(0));out.println(list.get(0));//此处省略了System}}GenericBooleanf1=newGenericBoolean();GenericIntegerf2=newGenericInteger();f1=f2;//发生编译错误incompatibletypesfound:Genericjava.lang.Integerrequired:Genericjava.lang.Booleanf1=f2;泛型类实例之间的赋值n同一泛型类,如果实例化时给定的实际类型不同,则这些实例的类型是不兼容的,不能相互赋值。泛型中的Object类型兼容性nObject是所有类的父类,因此,所有的类型的实例都可赋值给声明为Object类型的变量n在实例化泛型类时,将泛型指定为Object类型却不存在着和其他类型之间的兼容性:GenericBooleanf1=newGenericBoolean();GenericIntegerf2=newGenericInteger();GenericObjectf=f1;//f1和f类型并不兼容,发生编译错误f=f2;//f2和f类型同样不兼容,也会发生编译错误Booleanf1=newBoolean(true);Integerf2=newInteger(1);Objectf=f1;//OKf=f2;//OK泛型通配字符(Wildcard)n泛型类实例之间的不兼容性会带来使用的不便。n使用泛型通配符(?)声明泛型类的变量可以解决这个问题GenericBooleanf1=newGenericBoolean();GenericIntegerf2=newGenericInteger();GenericObjectf3=newGenericObject();//f可代表Generic所有可能的实例Generic?f;f=f1;//OKf=f2;//OKf=f3;//OK通配符用作方法的参数classUtil{//Collection?可以匹配任何强类型集合staticvoidprintCollection(Collection?c){for(Objecto:c)System.out.println(o);}}n通配符也可以用于方法的参数类型的声明,表示该参数可接受对应泛型类型的任意实例。n以下类定义中的printCollection方法可以打印任意强类型集合中的内容Generic?extendsListf=null;f=newGenericArrayList();//Ok.....f=newGenericVector();//OK....//以下语句会发生编译错误,因为HashMap没有实现List接口f=newGenricHashMap();为通配符指定匹配上限n和限制泛型的上限相似,同样可以使用extends关键字限定通配符匹配类型的上限:incompatibletypesfound:Genericjava.util.HashMaprequired:Generic?extendsjava.util.Listf=newGenericHashMap();//将f限定为只能代表采用java.sq