泛型java指南

上传人:第*** 文档编号:38826711 上传时间:2018-05-08 格式:DOC 页数:33 大小:247.50KB
返回 下载 相关 举报
泛型java指南_第1页
第1页 / 共33页
泛型java指南_第2页
第2页 / 共33页
泛型java指南_第3页
第3页 / 共33页
泛型java指南_第4页
第4页 / 共33页
泛型java指南_第5页
第5页 / 共33页
点击查看更多>>
资源描述

《泛型java指南》由会员分享,可在线阅读,更多相关《泛型java指南(33页珍藏版)》请在金锄头文库上搜索。

1、explorers 的专栏的专栏路漫漫其修远兮,吾将上下而求索路漫漫其修远兮,吾将上下而求索登录注册全站空间博客好友相册留言Java1.5 泛型指南中文版泛型指南中文版(Java1.5 Generic Tutorial)收藏收藏Java1.5 泛型指南中文版(Java1.5 Generic Tutorial)英文版 pdf 下载链接:http:/ 目 录摘要和关键字1. 介绍2. 定义简单的泛型3. 泛型和子类继承4. 通配符(Wildcards)4.1. 有限制的通配符(Bounded Wildcards)5. 泛型方法6. 与旧代码交互6.1. 在泛型代码中使用老代码6.2. 擦除和翻译(

2、Erasure and Translation)6.3. 在老代码中使用泛型代码7. 要点(The Fine Print)7.1. 一个泛型类被其所有调用共享7.2. 转型和 instanceof7.3. 数组 Arrays8. 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 p

3、arameter、wildcards(?)、unknown type、? extends T、? super T、erasure、translation、cast、instanceof、arrays、Class Literals as Run-time Type Tokens、wildcard capture、multiple bounds(T extends T1/ 1myIntList.add(new Integer(0);/ 2Integer x = (Integer) myIntList.iterator().next();/ 3第 3 行的类型转换有些烦人。通常情况下,程序员知道一个

4、特定的 list 里边放的是什么类型的数据。但是,这个类型转换是必须的(essential)。编译器只能保证 iterator 返回的是 Object 类型。为了保证对 Integer 类型变量赋值的类型安全,必须进行类型转换。当然,这个类型转换不仅仅带来了混乱,它还可能产生一个运行时错误(run time error),因为程序员可能会犯错。程序员如何才能明确表示他们的意图,把一个 list 中的内容限制为一个特定的数据类型呢?这是 generics 背后的核心思想。这是上面程序片断的一个泛型版本:List myIntList = new LinkedList(); / 1myIntList

5、.add(new Integer(0); / 2Integer x = myIntList.iterator().next(); / 3注意变量 myIntList 的类型声明。它指定这不是一个任意的 List,而是一个 Integer 的 List,写作:List。我们说 List 是一个带一个类型参数的泛型接口(a generic interface that takes a type parameter),本例中,类型参数是Integer。我们在创建这个 List 对象的时候也指定了一个类型参数。另一个需要注意的是第 3 行没了类型转换。 现在,你可能认为我们已经成功地去掉了程序里的混乱

6、。我们用第 1 行的类型参数取代了第 3 行的类型转换。然而,这里还有个很大的不同。编译器现在能够在编译时检查程序的正确性。当我们说 myIntList 被声明为 List类型,这告诉我们无论何时何地使用 myIntList 变量,编译器保证其中的元素的正确的类型。与之相反,一个类型转换说明程序员认为在那个代码点上它应该是那种类型。实际结果是,这可以增加可读性和稳定性(robustness),尤其在大型的程序中。2. 定义简单的泛型定义简单的泛型下面是从 java.util 包中的 List 接口和 Iterator 接口的定义中摘录的片断:public interface List void

7、 add(E x);Iterator iterator();public interface Iterator E next();boolean hasNext();这些都应该是很熟悉的,除了尖括号中的部分,那是接口 List 和 Iterator 中的形式类型参数的声明(the declarations of the formal type parameters of the interfaces List and Iterator)。类型参数在整个类的声明中可用,几乎是所有可是使用其他普通类型的地方(但是有些重要的限制,请参考第 7 部分)。(原文:Type parameters can

8、be used throughout the generic declaration, pretty much where you would use ordinary types (though there are some important restrictions; see section 7))在介绍那一节我们看到了对泛型类型声明 List(the generic type declaration List)的调用,如 List。在这个调用中(通常称作一个参数化类型 a parameterized type),所有出现形式类型参数(formal type parameter,这里是

9、E)都被替换成实体类型参数(actual type argument)(这里是 Integer)。你可能想象,List代表一个 E 被全部替换成 Integer 的版本:public interface IntegerList void add(Integer x)Iterator iterator();这种直觉可能有帮助,但是也可能导致误解。它有帮助,因为 List的声明确实有类似这种替换的方法。它可能导致误解,因为泛型声明绝不会实际的被这样替换。没有代码的多个拷贝,源码中没有、二进制代码中也没有;磁盘中没有,内存中也没有。如果你是一个 C+程序员,你会理解这是和 C+模板的很大的区别。一个

10、泛型类型的声明只被编译一次,并且得到一个 class 文件,就像普通的 class 或者 interface 的声明一样。类型参数就跟在方法或构造函数中普通的参数一样。就像一个方法有形式参数(formal value parameters)来描述它操作的参数的种类一样,一个泛型声明也有形式类型参数(formal type parameters)。当一个方法被调用,实参(actual arguments)替换形参,方法体被执行。当一个泛型声明被调用,实际类型参数(actual type arguments)取代形式类型参数。一个命名的习惯:我们推荐你用简练的名字作为形式类型参数的名字(如果可能,

11、单个字符)。最好避免小写字母,这使它和其他的普通的形式参数很容易被区分开来。许多容器类型使用 E 作为其中元素的类型,就像上面举的例子。在后面的例子中还会有一些其他的命名习惯。3. 泛型和子类继承泛型和子类继承让我们测试一下我们对泛型的理解。下面的代码片断合法么?List ls = new ArrayList(); /1List lo = ls; /2 第 1 行当然合法,但是这个问题的狡猾之处在于第 2 行。这产生一个问题:一个 String 的 List 是一个 Object 的 List 么?大多数人的直觉是回答:“当然!”。好,在看下面的几行:lo.add(new Object();

12、/ 3String s = ls.get(0); / 4: 试图把 Object 赋值给 String这里,我们使用 lo 指向 ls。我们通过 lo 来访问 ls,一个 String 的 list。我们可以插入任意对象进去。结果是 ls 中保存的不再是 String。当我们试图从中取出元素的时候,会得到意外的结果。java 编译器当然会阻止这种情况的发生。第 2 行会导致一个编译错误。总之,如果 Foo 是 Bar 的一个子类型(子类或者子接口),而 G 是某种泛型声明,那么 G是 G的子类型并不成立! 这可能是你学习泛型中最难理解的部分,因为它和你的直觉相反。这种直觉的问题在于它假定这个集

13、合不改变。我们的直觉认为这些东西都不可改变。举例来说,如果一个交通部(DMV)提供一个驾驶员里表给人口普查局,这似乎很合理。我们想,一个 List是一个 List,假定 Driver 是 Person 的子类型。实际上,我们传递的是一个驾驶员注册的拷贝。然而,人口普查局可能往驾驶员 list 中加入其他人,这破坏了交通部的记录。为了处理这种情况,考虑一些更灵活的泛型类型很有用。到现在为止我们看到的规则限制比较大。4. 通配符通配符(Wildcards)考虑写一个例程来打印一个集合(Collection)中的所有元素。下面是在老的语言中你可能写的代码:void printCollection(C

14、ollection c) Iterator i = c.iterator();for (int k = 0; k c) for (Object e : c) System.out.println(e); 问题是新版本的用处比老版本小多了。老版本的代码可以使用任何类型的 collection 作为参数,而新版本则只能使用 Collection,我们刚才阐述了,它不是所有类型的 collections 的父类。那么什么是各种 collections 的父类呢?它写作: Collection(发音为:“collection of unknown“),就是,一个集合,它的元素类型可以匹配任何类型。显然

15、,它被称为通配符。我们可以写:void printCollection(Collection c) for (Object e : c) System.out.println(e);现在,我们可以使用任何类型的 collection 来调用它。注意,我们仍然可以读取 c 中的元素,其类型是 Object。这永远是安全的,因为不管 collection 的真实类型是什么,它包含的都是 objects。但是将任意元素加入到其中不是类型安全的:Collection c = new ArrayList();c.add(new Object(); / 编译时错误因为我们不知道 c 的元素类型,我们不能向其中添加对象。add 方法有类型参数 E 作为集合的元素类型。我们传给 add 的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。唯一的例外是 null,它是所有类型的成员。另一方面,我们可以调用 get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个 Object,因此把 get 的返回值赋值给一个 Object 类型的对象或者放在任何希望是 Object 类型的地方是安全的。4.1. 有限制

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号