ImageVerifierCode 换一换
格式:DOCX , 页数:26 ,大小:37.44KB ,
资源ID:6479582      下载积分:2 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6479582.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(jdk15泛型指南中文版.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

jdk15泛型指南中文版.docx

1、jdk15泛型指南中文版Java1.5泛型指南中文版(Java1.5 Generic Tutorial)英文版pdf下载链接:译者:chengchengji目录摘要和关键字1.介绍2.定义简单的泛型3.泛型和子类继承4.通配符(Wildcards)4.1.有限制的通配符(Bounded Wildcards)5.泛型方法6.与旧代码交互6.1.在泛型代码中使用老代码6.2.擦除和翻译(Erasure and Translation)6.3.在老代码中使用泛型代码7.要点(The Fine Print)7.1.一个泛型类被其所有调用共享7.2.转型和instanceof7.3.数组Arrays8.

2、Class Literals as Run-time Type Tokens9.More fun with *9.1.通配符匹配(wildcard capture)10.泛型化老代码11.致谢摘要和关键字generics、type safe、type parameter(variable)、formal type parameter、actual type parameter、wildcards(?)、unknown type、? extends T、? super T、erasure、translation、cast、instanceof、arrays、Class Literals as R

3、un-time Type Tokens、wildcard capture、multiple bounds(T extends T1& T2 . & Tn)、covariant returns1.介绍JDK1.5中引入了对java语言的多种扩展,泛型(generics)即其中之一。这个教程的目标是向您介绍java的泛型(generic)。你可能熟悉其他语言的泛型,最著名的是C+的模板(templates)。如果这样,你很快就会看到两者的相似之处和重要差异。如果你不熟悉相似的语法结构,那么更好,你可以从头开始而不需要忘记误解。Generics允许对类型进行抽象(abstract over type

4、s)。最常见的例子是集合类型(Container types),Collection的类树中任意一个即是。下面是那种典型用法:List myIntList =newLinkedList();/ 1myIntList.add(newInteger(0);/ 2Integer x = (Integer)myIntList.iterator().next();/ 3第3行的类型转换有些烦人。通常情况下,程序员知道一个特定的list里边放的是什么类型的数据。但是,这个类型转换是必须的(essential)。编译器只能保证iterator返回的是Object类型。为了保证对Integer类型变量赋值的类

5、型安全,必须进行类型转换。当然,这个类型转换不仅仅带来了混乱,它还可能产生一个运行时错误(run time error),因为程序员可能会犯错。程序员如何才能明确表示他们的意图,把一个list中的内容限制为一个特定的数据类型呢?这是generics背后的核心思想。这是上面程序片断的一个泛型版本:List myIntList =newLinkedList();/ 1myIntList.add(newInteger(0);/ 2Integer x =myIntList.iterator().next();/ 3注意变量myIntList的类型声明。它指定这不是一个任意的List,而是一个Integ

6、er的List,写作:List。我们说List是一个带一个类型参数的泛型接口(a generic interface that takes a type parameter),本例中,类型参数是Integer。我们在创建这个List对象的时候也指定了一个类型参数。另一个需要注意的是第3行没了类型转换。现在,你可能认为我们已经成功地去掉了程序里的混乱。我们用第1行的类型参数取代了第3行的类型转换。然而,这里还有个很大的不同。编译器现在能够在编译时检查程序的正确性。当我们说myIntList被声明为List类型,这告诉我们无论何时何地使用myIntList变量,编译器保证其中的元素的正确的类型。与

7、之相反,一个类型转换说明程序员认为在那个代码点上它应该是那种类型。实际结果是,这可以增加可读性和稳定性(robustness),尤其在大型的程序中。2.定义简单的泛型下面是从java.util包中的List接口和Iterator接口的定义中摘录的片断:publicinterfaceList voidadd(E x);Iteratoriterator();publicinterfaceIterator Enext();booleanhasNext();这些都应该是很熟悉的,除了尖括号中的部分,那是接口List和Iterator中的形式类型参数的声明(the declarations of the

8、 formal type parameters of the interfaces List and Iterator)。类型参数在整个类的声明中可用,几乎是所有可是使用其他普通类型的地方(但是有些重要的限制,请参考第7部分)。(原文:Type parameters can be used throughout the generic declaration, pretty much where you would use ordinary types (though there are some important restrictions; see section 7))在介绍那一节我们看

9、到了对泛型类型声明List(the generic type declaration List)的调用,如List。在这个调用中(通常称作一个参数化类型a parameterized type),所有出现形式类型参数(formal type parameter,这里是E)都被替换成实体类型参数(actual type argument)(这里是Integer)。你可能想象,List代表一个E被全部替换成Integer的版本:publicinterfaceIntegerList voidadd(Integer x)Iteratoriterator();这种直觉可能有帮助,但是也可能导致误解。它有

10、帮助,因为List的声明确实有类似这种替换的方法。它可能导致误解,因为泛型声明绝不会实际的被这样替换。没有代码的多个拷贝,源码中没有、二进制代码中也没有;磁盘中没有,内存中也没有。如果你是一个C+程序员,你会理解这是和C+模板的很大的区别。一个泛型类型的声明只被编译一次,并且得到一个class文件,就像普通的class或者interface的声明一样。类型参数就跟在方法或构造函数中普通的参数一样。就像一个方法有形式参数(formal value parameters)来描述它操作的参数的种类一样,一个泛型声明也有形式类型参数(formal type parameters)。当一个方法被调用,实

11、参(actual arguments)替换形参,方法体被执行。当一个泛型声明被调用,实际类型参数(actual type arguments)取代形式类型参数。一个命名的习惯:我们推荐你用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母,这使它和其他的普通的形式参数很容易被区分开来。许多容器类型使用E作为其中元素的类型,就像上面举的例子。在后面的例子中还会有一些其他的命名习惯。3.泛型和子类继承让我们测试一下我们对泛型的理解。下面的代码片断合法么?List ls = new ArrayList(); /1List lo = ls; /2第1行当然合法,但是这个问题的狡猾

12、之处在于第2行。这产生一个问题:一个String的List是一个Object的List么?大多数人的直觉是回答:“当然!”。好,在看下面的几行:lo.add(new Object(); / 3String s = ls.get(0); / 4:试图把Object赋值给String这里,我们使用lo指向ls。我们通过lo来访问ls,一个String的list。我们可以插入任意对象进去。结果是ls中保存的不再是String。当我们试图从中取出元素的时候,会得到意外的结果。java编译器当然会阻止这种情况的发生。第2行会导致一个编译错误。总之,如果Foo是Bar的一个子类型(子类或者子接口),而G是

13、某种泛型声明,那么G是G的子类型并不成立!这可能是你学习泛型中最难理解的部分,因为它和你的直觉相反。这种直觉的问题在于它假定这个集合不改变。我们的直觉认为这些东西都不可改变。举例来说,如果一个交通部(DMV)提供一个驾驶员里表给人口普查局,这似乎很合理。我们想,一个List是一个List,假定Driver是Person的子类型。实际上,我们传递的是一个驾驶员注册的拷贝。然而,人口普查局可能往驾驶员list中加入其他人,这破坏了交通部的记录。为了处理这种情况,考虑一些更灵活的泛型类型很有用。到现在为止我们看到的规则限制比较大。4.通配符(Wildcards)考虑写一个例程来打印一个集合(Coll

14、ection)中的所有元素。下面是在老的语言中你可能写的代码:voidprintCollection(Collection c) Iterator i =c.iterator();for(intk = 0; k c.size(); k+) System.out.println(i.next();下面是一个使用泛型的幼稚的尝试(使用了新的循环语法):voidprintCollection(Collection c) for(Object e : c) System.out.println(e);问题是新版本的用处比老版本小多了。老版本的代码可以使用任何类型的collection作为参数,而新版本

15、则只能使用Collection,我们刚才阐述了,它不是所有类型的collections的父类。那么什么是各种collections的父类呢?它写作:Collection(发音为:collection of unknown),就是,一个集合,它的元素类型可以匹配任何类型。显然,它被称为通配符。我们可以写:voidprintCollection(Collection c) for(Object e : c) System.out.println(e);现在,我们可以使用任何类型的collection来调用它。注意,我们仍然可以读取c中的元素,其类型是Object。这永远是安全的,因为不管colle

16、ction的真实类型是什么,它包含的都是objects。但是将任意元素加入到其中不是类型安全的:Collection c =newArrayList();c.add(newObject();/编译时错误因为我们不知道c的元素类型,我们不能向其中添加对象。add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。唯一的例外是null,它是所有类型的成员。另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object,因此把get的返回值赋值给一个Objec

17、t类型的对象或者放在任何希望是Object类型的地方是安全的。4.1.有限制的通配符(Bounded Wildcards)考虑一个简单的画图程序,它可以用来画各种形状,比如矩形和圆形。为了在程序中表示这些形状,你可以定义下面的类继承结构:publicabstractclassShape publicabstractvoiddraw(Canvas c);publicclassCircleextendsShape privateintx,y,radius;publicvoiddraw(Canvas c) / .publicclassRectangleextendsShape privateintx

18、,y,width,height;publicvoiddraw(Canvas c) / .这些类可以在一个画布(Canvas)上被画出来:publicclassCanvas publicvoiddraw(Shape s) s.draw(this);所有的图形通常都有很多个形状。假定它们用一个list来表示,Canvas里有一个方法来画出所有的形状会比较方便:publicvoiddrawAll(List shapes) for(Shape s : shapes) s.draw(this);现在,类型规则导致drawAll()只能使用Shape的list来调用。它不能,比如说对List来调用。这很不

19、幸,因为这个方法所作的只是从这个list读取shape,因此它应该也能对List调用。我们真正要的是这个方法能够接受一个任意种类的shape:publicvoiddrawAll(List shapes) /.这里有一处很小但是很重要的不同:我们把类型List替换成了List。现在drawAll()可以接受任何Shape的子类的List,所以我们可以对List进行调用。List是有限制通配符的一个例子。这里?代表一个未知的类型,就像我们前面看到的通配符一样。但是,在这里,我们知道这个未知的类型实际上是Shape的一个子类(它可以是Shape本身或者Shape的子类而不必是extends自Shap

20、e)。我们说Shape是这个通配符的上限(upper bound)。像平常一样,要得到使用通配符的灵活性有些代价。这个代价是,现在像shapes中写入是非法的。比如下面的代码是不允许的:publicvoidaddRectangle(List shapes) shapes.add(0,newRectangle();/ compile-time error!你应该能够指出为什么上面的代码是不允许的。因为shapes.add的第二个参数类型是?extendsShape一个Shape未知的子类。因此我们不知道这个类型是什么,我们不知道它是不是Rectangle的父类;它可能是也可能不是一个父类,所以这

21、里传递一个Rectangle不安全。有限制的通配符正是我们解决DMV给人口普查局传送名单的例子所需要的。我们的例子假定数据用一个姓名(String)到people(用Person或其子类来表示,比如Driver)。Map是一个有两个类型参数的泛型类型的例子,表示map的键key和值value。再一次,注意形式类型参数的命名习惯K代表keys,V代表vlaues。publicclassCensuspublicstatic voidaddRegistry(Mapregistry).MapallDrivers = .;Census.addRegistry(allDrivers);5.泛型方法考虑写一

22、个方法,它用一个Object的数组和一个collection作为参数,完成把数组中所有object放入collection中的功能。下面是第一次尝试:staticvoidfromArrayToCollection(Object a, Collectionc)for(Object o : a)c.add(o);/编译期错误现在,你应该能够学会避免初学者试图使用Collection作为集合参数类型的错误了。或许你已经意识到使用Collection也不能工作。会议一下,你不能把对象放进一个未知类型的集合中去。解决这个问题的办法是使用generic methods。就像类型声明,方法的声明也可以被泛型

23、化就是说,带有一个或者多个类型参数。staticvoidfromArrayToCollection(T a, Collection c)for(T o : a) c.add(o);/ correct我们可以使用任意集合来调用这个方法,只要其元素的类型是数组的元素类型的父类。Object oa =newObject100;Collection co =newArrayList();fromArrayToCollection(oa, co);/ T指ObjectString sa =newString100;Collection cs =newArrayList();fromArrayToColl

24、ection(sa, cs);/ T inferred to be StringfromArrayToCollection(sa, co);/ T inferred to be ObjectInteger ia =newInteger100;Float fa =newFloat100;Number na =newNumber100;Collection cn =newArrayList();fromArrayToCollection(ia, cn);/ T inferred to be NumberfromArrayToCollection(fa, cn);/ T inferred to be

25、 NumberfromArrayToCollection(na, cn);/ T inferred to be NumberfromArrayToCollection(na, co);/ T inferred to be ObjectfromArrayToCollection(na, cs);/ compile-time error注意,我们并没有传送真实类型参数(actual type argument)给一个泛型方法。编译器根据实参为我们推断类型参数的值。它通常推断出能使调用类型正确的最明确的类型参数(原文是:It will generallyinferthe most specific

26、type argument that will make the call type-correct.)。现在有一个问题:我们应该什么时候使用泛型方法,又什么时候使用通配符类型呢?为了理解答案,让我们先看看Collection库中的几个方法。publicinterfaceCollection booleancontainsAll(Collection c);booleanaddAll(Collection c);我们也可以使用泛型方法来代替:publicinterfaceCollection booleancontainsAll(Collection c);booleanaddAll(Collection c);/hey, type variables can have bounds too!但是,在containsAll和addAll中,类型参数T都只使用一次。返回值的类型既不依赖于类型参数(type parameter)也不依赖于方法的其他参数(这里,只有简单的一个参数)。这告诉我们类型参数(type argument)被用作多态(polymorphism),它唯一的效果是允许在不同的调用点,可以使用多种实参类型(actual argument)。如果是这种情况,应该使用通配符。通配符就是被设计用来支持灵活的子类化的,这是我们在这里要强调的。泛型函数允

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1