




已阅读5页,还剩24页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java泛型总结报告精选 1.什么是泛型? 泛型(Generictype或者generics)是对Java语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。 可以在集合框架(Collectionframework)中看到泛型的动机。例如,Map类允许您向一个Map添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如String)的对象。 因为Map.get()被定义为返回Object,所以一般必须将Map.get()的结果强制类型转换为期望的类型,如下面的代码所示: Mapm=newHashMap(); m.put(key,blarg); Strings=(String)m.get(key); 要让程序通过编译,必须将get()的结果强制类型转换为String,并且希望结果真的是一个String。但是有可能某人已经在该映射中保存了不是String的东西,这样的话,上面的代码将会抛出ClassCastException。 理想情况下,您可能会得出这样一个观点,即m是一个Map,它将String键映射到String值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。 2.泛型的好处 Java语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处: 类型安全。泛型的主要目标是提高Java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。 Java程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“String列表”或者“String到String的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作ClassCastException展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。 消除强制类型转换。泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。 尽管减少强制类型转换可以降低使用泛型类的代码的罗嗦程度,但是声明泛型变量会带来相应的罗嗦。比较下面两个代码例子。 该代码不使用泛型: Listli=newArrayList(); li.put(newInteger(3); Integeri=(Integer)li.get(0); 该代码使用泛型: Listli=newArrayList(); li.put(newInteger(3); Integeri=li.get(0); 在简单的程序中使用一次泛型变量不会降低罗嗦程度。但是对于多次使用泛型变量的大型程序来说,则可以累积起来降低罗嗦程度。 潜在的性能收益。泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的JVM的优化带来可能。 由于泛型的实现方式,支持泛型(几乎)不需要JVM或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。 3.泛型用法的例子 泛型的许多最佳例子都集合框架,因为泛型让您在保存在集合中的元素上指定类型约束。考虑这个使用Map类的例子,其中涉及一定程度的优化,即Map.get()返回的结果将确实是一个String: Mapm=newHashMap(); m.put(key,blarg); Strings=(String)m.get(key); 如果有人已经在映射中放置了不是String的其他东西,上面的代码将会抛出ClassCastException。泛型允许您表达这样的类型约束,即m是一个将String键映射到String值的Map。这可以消除代码中的强制类型转换,同时获得一个附加的类型检查层,这个检查层可以防止有人将错误类型的键或值保存在集合中。 下面的代码示例展示了JDK5.0中集合框架中的Map接口的定义的一部分: publicinterfaceMap publicvoidput(Kkey,Vvalue); publicVget(Kkey); 注意该接口的两个附加物: 类型参数K和V在类级别的规格说明,表示在声明一个Map类型的变量时指定的类型的占位符。 在get()、put()和其他方法的方法签名中使用的K和V。 为了赢得使用泛型的好处,必须在定义或实例化Map类型的变量时为K和V提供具体的值。以一种相对直观的方式做这件事: Mapm=newHashMap(); m.put(key,blarg); Strings=m.get(key); 当使用Map的泛型化版本时,您不再需要将Map.get()的结果强制类型转换为String,因为编译器知道get()将返回一个String。 在使用泛型的版本中并没有减少键盘录入;实际上,比使用强制类型转换的版本需要做更多键入。使用泛型只是带来了附加的类型安全。因为编译器知道关于您将放进Map中的键和值的类型的更多信息,所以类型检查从执行时挪到了编译时,这会提高可靠性并加快开发速度。 向后兼容 在Java语言中引入泛型的一个重要目标就是维护向后兼容。尽管JDK5.0的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类(比如HashMap和ArrayList)的现有代码将继续不加修改地在JDK5.0中工作。当然,没有利用泛型的现有代码将不会赢得泛型的类型安全好处。 4.泛型基础 4.1类型参数 在定义泛型类或声明泛型类的变量时,使用尖括号来指定形式类型参数。形式类型参数与实际类型参数之间的关系类似于形式方法参数与实际方法参数之间的关系,只是类型参数表示类型,而不是表示值。 泛型类中的类型参数几乎可以用于任何可以使用类名的地方。例如,下面是java.util.Map接口的定义的摘录: publicinterfaceMap publicvoidput(Kkey,Vvalue); publicVget(Kkey); Map接口是由两个类型参数化的,这两个类型是键类型K和值类型V。(不使用泛型)将会接受或返回Object的方法现在在它们的方法签名中使用K或V,指示附加的类型约束位于Map的规格说明之下。 当声明或者实例化一个泛型的对象时,必须指定类型参数的值: Mapmap=newHa shMap(); 注意,在本例中,必须指定两次类型参数。一次是在声明变量map的类型时,另一次是在选择HashMap类的参数化以便可以实例化正确类型的一个实例时。 编译器在遇到一个Map类型的变量时,知道K和V现在被绑定为String,因此它知道在这样的变量上调用Map.get()将会得到String类型。 除了异常类型、枚举或匿名内部类以外,任何类都可以具有类型参数。 4.2命名类型参数 推荐的命名约定是使用大写的单个字母名称作为类型参数。这与C+约定有所不同(参阅附录A:与C+模板的比较),并反映了大多数泛型类将具有少量类型参数的假定。对于常见的泛型模式,推荐的名称是: K键,比如映射的键。 V值,比如List和Set的内容,或者Map中的值。 E异常类。 T泛型。 4.3泛型不是协变的 关于泛型的混淆,一个常见的就是假设它们像数组一样是协变的。其实它们不是协变的。List 不是List的父类型。 如果A扩展B,那么A的数组也是B的数组,并且完全可以在需要B的地方使用A: IntegerintArray=newInteger10; NumbernumberArray=intArray; 上面的代码是有效的,因为一个Integer是一个Number,因而一个Integer数组是一个Number数组。但是对于泛型来说则不然。下面的代码是无效的: ListintList=newArrayList(); ListnumberList=intList;/invalid 最初,大多数Java程序员觉得这缺少协变很烦人,或者甚至是“坏的(broken)”,但是之所以这样有一个很好的原因。如果可以将List赋给List,下面的代码就会违背泛型应该提供的类型安全: ListintList=newArrayList(); ListnumberList=intList;/invalid numberList.add(newFloat(3.1415); 因为intList和numberList都是有别名的,如果允许的话,上面的代码就会让您将不是Integers的东西放进intList中。但是,正如下一屏将会看到的,您有一个更加灵活的方式来定义泛型。 4.4类型通配符 假设您具有该方法: voidprintList(Listl) for(Objecto:l) System.out.println(o); 上面的代码在JDK5.0上编译通过,但是如果试图用List调用它,则会得到警告。出现警告是因为,您将泛型(List)传递给一个只承诺将它当作List(所谓的原始类型)的方法,这将破坏使用泛型的类型安全。 如果试图编写像下面这样的方法,那么将会怎么样? voidprintList(List l) for(Objecto:l) System.out.println(o); 它仍然不会通过编译,因为一个List不是一个List (正如前一屏泛型不是协变的中所学的)。这才真正烦人现在您的泛型版本还没有普通的非泛型版本有用! 解决方案是使用类型通配符: voidprintList(Listl) for(Objecto:l) System.out.println(o); 上面代码中的问号是一个类型通配符。它读作“问号”。List是任何泛型List的父类型,所以您完全可以将List 、List或List传递给printList()。 4.5类型通配符的作用 类型通配符中引入了类型通配符,这让您可以声明List类型的变量。您可以对这样的List做什么呢?非常方便,可以从中检索元素,但是不能添加元素。原因不是编译器知道哪些方法修改列表哪些方法不修改列表,而是(大多数)变化的方法比不变化的方法需要更多的类型信息。下面的代码则工作得很好: Listli=newArrayList(); li.add(newInteger(42); Listlu=li; System.out.println(lu.get(0); 为什么该代码能工作呢?对于lu,编译器一点都不知道List的类型参数的值。但是编译器比较聪明,它可以做一些类型推理。在本例中,它推断的类型参数必须扩展Object。(这个特定的推理没有太大的跳跃,但是编译器可以作出一些非常令人佩服的类型推理,后面就会看到(在底层细节一节中)。所以它让您调用List.get()并推断返回类型为Object。另一方面,下面的代码不能工作: Listli=newArrayList(); li.add(newInteger(42); Listlu=li; lu.add(newInteger(43);/error 在本例中,对于lu,编译器不能对List的类型参数作出足够严密的推理,以确定将Integer传递给List.add()是类型安全的。所以编译器将不允许您这么做。 以免您仍然认为编译器知道哪些方法更改列表的内容哪些不更改列表内容,请注意下面的代码将能工作,因为它不依赖于编译器必须知道关于lu的类型参数的任何信息: Listli=newArrayList(); li.add(newInteger(42); Listlu=li; lu.clear(); 4.6泛型方法 (在类型参数一节中)您已经看到,通过在类的定义中添加一个形式类型参数列表,可以将类泛型化。方法也可以被泛型化,不管它们定义在其中的类是不是泛型化的。 泛型类在多个方法签名间实施类型约束。在List中,类型参数V出现在get()、add()、contains()等方法的签名中。当创建一个Map类型的变量时,您就在方法之间宣称一个类型约束。您传递给add()的值将与get()返回的值的类型相同。 类似地,之所以声明泛型方法,一般是因为您想要在该方法的多个参数之间宣称一个类型约束。例如,下面代码中的ifThenElse()方法,根据它的第一个参数的布尔值,它将返回第二个或第三个参数: publicTifThenElse(booleanb,Tfirst,Tsecond) returnb?first:second; 注意,您可以调用ifThenElse(),而不用显式地告诉编译器,您想要T的什么值。编译器不必显式地被告知T将具有什么值;它只知道这些值都必须相同。编译器允许您调用下面的代码,因为编译器可以使用类型推理来推断出,替代T的String满足所有的类型约束:Strings=ifThenElse(b,a,b); 类似地,您可以调用: Integeri=ifThenElse(b,newInteger(1),newInteger(2); 但是,编译器不允许下面的代码,因为没有类型会满足所需的类型约束: Strings=ifThenElse(b,pi,newFloat(3.14); 为什么您选择使用泛型方法,而不是将类型T添加到类定义呢?(至少)有两种情况应该这样做: 当泛型方法是静态的时,这种情况下不能使用类类型参数。 当T上的类型约束对于方法真正是局部的时,这意味着没有在相同类的另一个方法签名中使用相同类型T的约束。通过使得泛型方法的类型参数对于方法是局部的,可以简化封闭类型的签名。 4.7有限制类型 在前一屏泛型方法的例子中,类型参数V是无约束的或无限制的类型。有时在还没有完全指定类型参数时,需要对类型参数指定附加的约束。 考虑例子Matrix类,它使用类型参数V,该参数由Number类来限制: publicclassMatrix. 编译器允许您创建Matrix或Matrix类型的变量,但是如果您试图定义 Java泛型 Java泛型是java1.5中引入的新特性,在此之前,java通过对类型Object的引用来实现参数类型的“任意化”,特点则是需要进行显示的强制类型转换。(而这种显示的类型转换可能是无法进行的,是错误的)但编译器无法发现强制类型转换可能引起的异常,异常只有在运行时才能出现,成为了系统的安全隐患。-为啥要进入泛型这个概念泛型的本质是参数化类型,及所操作的数据类型被指定为一个参数,此参数类型可以用在类、接口、和方法的声明及创建中,分别被称为泛型类,泛型接口,及泛型方法。使用注意事项: 泛型的类型参数只能是类类型(包括自定义类),但是不能是简单类型泛型类型参数可以是多个 泛型的参数类型还可以是通配符类型 没有泛型的错误: Importjava.util.*; PublicclassNoGenericTypeDemo Publicstaticvoidmain(Stringargs) Listnames=newArrayList(); Names.add(张桑拿); Names.add(newInteger(2); StringnameFirst=(String)names.get(0); Stringnamesecond=(String)names.get(1);/抛出异常jav.lang.ClassCastException异常,而且编译时没有被发现 有时候需要使泛型变量能使用任何的类型,此时可以使用通配符”?”否则可能需要编写许多版本的重载函数,使用通配符,使方法printLsit()可以接受各种类型的List对象,否则必须使用重载技术, PublicstaticvoidprintList(Listlist) /输出集合中的元素 简单普通类 packagetest7; importjava.util.ArrayList; classStudent intNumber; StringName; StringCla; publicintGetNumber() returnNumber; publicvoidSetNumber(intNumber) this.Number=Number; publicStringGetName() returnName; publicvoidSetName(StringName) this.Name=Name; publicStringGetCla() returnCla; publicvoidSetCla(StringCla) this.Cla=Cla; publicStudent() publicStudent(intNumber,StringName,StringCla) this.Number=Number; this.Name=Name; this.Cla=Cla; publicclasstest071 publicstaticvoidmain(Stringargs) System.out.println(设计者:); Students1=newStudent(123,张三,11计科); Students2=newStudent(124,李四,11计科); Students3=newStudent(125,王五,11计科); Studentdujingjing=newStudent(xx0105,杜,11计科); ArrayListAL=newArrayList(); AL.add(s1); AL.add(s2); AL.add(s3); AL.add(dujingjing); for(inti=0;i Students=(Student)AL.get(i); System.out.println(学号:+s.Number+姓名:+s.Name+班级:+s.Cla); 简单泛型实例 java中泛型定义 Java的泛型类就是一个用类型作为参数的类,即带有参数化类型的类。就像我们定义类的成员方法一样。大家很熟悉Java的成员方法形式是method(Stringstr,inti),方法中参数str、i的值是可变的。而泛型也是一样的:class泛型类类名,这里的K和V就像方法中的参数str和i,也是可变的。 ClassUseT PrivateTx; PublicSetX(Tx) packagetest7; 泛型类:L2 classL2 privateTobj; publicL2(Tobj) this.obj=obj; publicTgetobj() returnthis.obj; publicvoidsetobj(Tobj) this.obj=obj; publicvoidshowobj(Tobj) System.out.println(数据为:+this.obj); 主类: publicclasstest072 publicstaticvoidmain(Stringargs) System.out.println(设计者:); L2name=newL2(汽车);name.showobj(name.getobj(); L2data=newL2(12);data.showobj(data.getobj(); 简单集合类 泛型总结篇: 1)泛型参数只能是类类型 例如:List/报错 List/正确 2)泛型的类型参数可以有多个! 例如:Listlist=new ArrayList(); 3)泛型的参数类型可以使用extends,习惯称“有界类型”, 例如:List,person为list的上界 4)泛型可以使用通配符类型!“?”相当于“Object”类型,(注意不可逆)例如:List/定义成这样可以添加Object类型到List里面去List ;/定义成这样不可以添加String类型到List里面去List;/这样就可以互等了!这样还可以设定泛型的上限 5)带泛型的类,构造方法写法不变,其后不可以加泛型! 例如:classStudent publicStudent()/构造方法这样写就错了 6)List不是List 的子类!,不可以把前者看成后者的子类,所以不 可以把前者的实例赋给后者 例如:ListSlist=newArrayList(); Slist.add(newString(abc); List Olist=newArrayList (); Olist.add(abc); Olist=Slist;/报错! 7)带不同泛型参数的实例可以共享类的静态方法和静态变量,所以静态方法和静态变量 申明的时候不可以使用类型行参 例如:classCup staticTinfo;/报错! publicstaticsetInfo(Tinfo);/报错! 8)带不同泛型参数的类是共享一个字节码文件的!反编译过后泛型参数就被擦除了 例如:ListSlist=newArrayList(); Slist.add(newString(aaa); ListIlist=newArrayList(); Ilist.add(newInteger(100); System.out.println(Slist.getClass()=Ilist.getClass();结果为true; 9)当使用定义了泛型参数的接口和父类的时候!就不能在带参数了例如:classSubextendsFather/错误 10) classT publicclasstypeTestextendsT/报错 classT publicclasstypeTestextendsT/正确可使用String等基本封装类型 classT classStudent publicclasstypeTestextendsT/这样也正确 11)泛型方法,泛型方法的参数的作用域仅在本方法,要和方法带泛型区分开!Staticvoidtest(ListS_list)/泛型参数要放在返回类型前 12)带有泛型的代码转换成没有泛型的代码由javac完成,虚拟机不处理这些事情! 这种技术叫做“擦除”; 例如:classFood Tsize; publicFood(Tsize)/注意构造方法不可以带泛型参数! publicvoidsetSize()this.size=size; publicTgetSize()returnthis.size; publicclasstest publicstaticvoidmain(Stringarg) Fooda=newFood(6); Ingegeras=a.getSize();/返回的是Integer的类型Foodb=a;/把a对象赋给Food变量;泛型参数类型会丢失即擦除; Numbersize1=b.getSize();/b只知道size的类型是Number/Integerin=b.getSize();这样是编译错误的! 导读:本文是从JavaGenericsQuickTutorial这篇文章翻译而来,译文外刊IT评论Java泛型简明教程。内容如下: 泛型是JavaSE5.0中引入的一项特征,自从这项语言特征出现多年来,我相信,几乎所有的Java程序员不仅听说过,而且使用过它。关于Java泛型的教程,的,不的,有很多。我遇到的最好的教材有: TheJavaTutorial JavaGenericsandCollections,byMauriceNaftalinandPhilipWadler EffectiveJava中文版(第2版),byJoshuaBloch. 尽管有这么多丰富的资料,有时我感觉,有很多的程序员仍然不太明白Java泛型的功能和意义。这就是为什么我想使用一种最简单的形式来总结一下程序员需要知道的关于Java泛型的最基本的知识。 Java泛型由来的动机 理解Java泛型最简单的方法是把它看成一种便捷语法,能节省你某些Java类型转换(casting)上的操作: 1.Listbox=.; 2.Appleapple=box.get(0); 上面的代码自身已表达的很清楚:box是一个装有Apple对象的List。get方法返回一个Apple对象实例,这个过程不需要进行类型转换。没有泛型,上面的代码需要写成这样: 1.Listbox=.; 2.Appleapple=(Apple)box.get(0); 很明显,泛型的主要好处就是让编译器保留参数的类型信息,执行类型检查,执行类型转换操作:编译器保证了这些类型转换的绝对无误。 相对于依赖程序员来记住对象类型、执行类型转换这会导致程序运行时的失败,很难调试和解决,而编译器能够帮助程序员在编译时强制进行大量的类型检查,发现其中的错误。泛型的构成 由泛型的构成引出了一个类型变量的概念。根据Java语言规范,类型变量是一种没有限制的标志符,产生于以下几种情况: 泛型类声明 泛型接口声明 泛型方法声明 泛型构造器(constructor)声明 泛型类和接口 如果一个类或接口上有一个或多个类型变量,那它就是泛型。类型变量由尖括号界定,放在类或接口名的后面: 1.publicinterfaceListextendsCollection 2. 3. 4. 简单的说,类型变量扮演的角色就如同一个参数,它提供给编译器用来类型检查的信息。Java类库里的很多类,例如整个Collection框架都做了泛型化的修改。例如,我们在上面的第一段代码里用到的List接口就是一个泛型类。在那段代码里,box是一个List对象,它是一个带有一个Apple类型变量的List接口的类实现的实例。编译器使用这个类型变量参数在get方法被调用、返回一个Apple对象时自动对其进行类型转换。实际上,这新出现的泛型标记,或者说这个List接口里的get方法是这样的: 1.Tget(intindex); get方法实际返回的是一个类型为T的对象,T是在List声明中的类型变量。泛型方法和构造器(Constructor) 非常的相似,如果方法和构造器上声明了一个或多个类型变量,它们也可以泛型化。 1.publicstaticTgetFirst(Listlist) 这个方法将会接受一个List类型的参数,返回一个T类型的对象。 例子 你既可以使用Java类库里提供的泛型类,也可以使用自己的泛型类。 类型安全的写入数据 下面的这段代码是个例子,我们创建了一个List实例,然后装入一些数据: 1.Liststr=newArrayList(); 2. 3.str.add(Hello); 4. 5.str.add(World.); 如果我们试图在List装入另外一种对象,编译器就会提示错误: 1.str.a
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 甘肃对口升学试卷及答案
- 卡姿莱特家居培训知识课件
- 2025年中考化学试卷题目及答案
- 烟雨密封测试题及答案
- 2025年电与力学结合试题及答案
- 2025年护士临床培训试卷及答案
- 汽油散装 采购合同7篇
- 医学刮痧基础知识培训
- 2025-2030中国眼科屈光手术设备技术迭代与市场教育投入研究
- 2025-2030中国盐化工市场准入门槛与行业壁垒突破路径研究报告
- 2025四川成都高新投资集团有限公司选聘中高层管理人员4人笔试参考题库附答案解析
- 湖南省九校联盟2026届高三上学期9月第一次联考物理试题(含答案)
- 水利工程水利工程施工技术规范
- 从安全感缺失剖析《榆树下的欲望》中爱碧的悲剧根源与启示
- 2025中证金融研究院招聘11人考试参考题库及答案解析
- 人教版(2024)八年级上册英语Unit 2 Home Sweet Home教案
- 城镇住宅建设调查技术实施方案
- 渔民安全培训课件
- 时空数据建模与预测算法-洞察阐释
- 汽车电路原理培训课件
- 2025年长江引航中心招聘笔试备考题库(带答案详解)
评论
0/150
提交评论