`
JAVA天地
  • 浏览: 673784 次
  • 性别: Icon_minigender_1
  • 来自: 太原
文章分类
社区版块
存档分类
最新评论

Java1.5泛型指南中文版(Java1.5 Generic Tutorial)

阅读更多

转自:http://blog.csdn.net/explorers/archive/2005/08/15/454837.aspx

Java1.5泛型指南中文版(Java1.5 Generic Tutorial)

英文版pdf下载链接:http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

译者: chengchengji@163.com

摘要和关键字... 1

1. 介绍... 1

2. 定义简单的泛型... 2

3. 泛型和子类继承... 3

4. 通配符(Wildcards). 4

4.1. 有限制的通配符(Bounded Wildcards). 5

5. 型方法... 6

6. 与旧代码交互... 9

6.1. 在泛型代码中使用老代码... 9

6.2. 擦除和翻译(Erasure and Translation). 10

6.3. 在老代码中使用泛型代码... 11

7. 要点(The Fine Print). 12

7.1. 一个泛型类被其所有调用共享... 12

7.2. 转型和instanceof 13

7.3. 数组Arrays. 13

8. Class Literals as Run-time Type Tokens. 14

9. More fun with *. 16

9.1. 通配符匹配(wildcard capture). 18

10. 泛型化老代码... 18

11. 致谢... 20

摘要和关键字

genericstype safetype parameter(variable)formal type parameteractual type parameterwildcards(?)unknown type? extends T? super TerasuretranslationcastinstanceofarraysClass Literals as Run-time Type Tokenswildcard capturemultiple bounds(T extends T1& T2 ... & Tn)covariant returns


1. 介绍

JDK1.5中引入了对java语言的多种扩展,泛型(generics)即其中之一。

这个教程的目标是向您介绍java的泛型(generic)。你可能熟悉其他语言的泛型,最著名的是C++的模板(templates)。如果这样,你很快就会看到两者的相似之处和重要差异。如果你不熟悉相似的语法结构,那么更好,你可以从头开始而不需要忘记误解。

Generics允许对类型进行抽象(abstract over types)。最常见的例子是集合类型(Container types)Collection的类树中任意一个即是。

下面是那种典型用法:

List myIntList = new LinkedList();// 1

myIntList.add(new Integer(0));// 2

Integer x = (Integer) myIntList.iterator().next();// 3

3行的类型转换有些烦人。通常情况下,程序员知道一个特定的list里边放的是什么类型的数据。但是,这个类型转换是必须的(essential)。编译器只能保证iterator返回的是Object类型。为了保证对Integer类型变量赋值的类型安全,必须进行类型转换。

当然,这个类型转换不仅仅带来了混乱,它还可能产生一个运行时错误(run time error),因为程序员可能会犯错。

程序员如何才能明确表示他们的意图,把一个list中的内容限制为一个特定的数据类型呢?这是generics背后的核心思想。这是上面程序片断的一个泛型版本:

List<Integer> myIntList = new LinkedList<Integer>(); // 1

myIntList.add(new Integer(0)); // 2

Integer x = myIntList.iterator().next(); // 3

注意变量myIntList的类型声明。它指定这不是一个任意的List,而是一个IntegerList,写作:List<Integer>。我们说List是一个带一个类型参数的泛型接口(a generic interface that takes a type parameter),本例中,类型参数是Integer。我们在创建这个List对象的时候也指定了一个类型参数。

另一个需要注意的是第3行没了类型转换。

现在,你可能认为我们已经成功地去掉了程序里的混乱。我们用第1行的类型参数取代了第3行的类型转换。然而,这里还有个很大的不同。编译器现在能够在编译时检查程序的正确性。当我们说myIntList被声明为List<Integer>类型,这告诉我们无论何时何地使用myIntList变量,编译器保证其中的元素的正确的类型。与之相反,一个类型转换说明程序员认为在那个代码点上它应该是那种类型。

实际结果是,这可以增加可读性和稳定性(robustness),尤其在大型的程序中。

2. 定义简单的泛型

下面是从java.util包中的List接口和Iterator接口的定义中摘录的片断:

public interface List<E> {

void add(E x);

Iterator<E> iterator();

}

public interface Iterator<E> {

E next();

boolean hasNext();

}

这些都应该是很熟悉的,除了尖括号中的部分,那是接口ListIterator中的形式类型参数的声明(the declarations of the 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)

在介绍那一节我们看到了对泛型类型声明List(the generic type declaration List)的调用,如List<Integer>。在这个调用中(通常称作一个参数化类型a parameterized type),所有出现形式类型参数(formal type parameter,这里是E)都被替换成实体类型参数(actual type argument)(这里是Integer)

你可能想象,List<Integer>代表一个E被全部替换成Integer的版本:

public interface IntegerList {

void add(Integer x)

Iterator<Integer> iterator();

}

这种直觉可能有帮助,但是也可能导致误解。

它有帮助,因为List<Integer>的声明确实有类似这种替换的方法。

它可能导致误解,因为泛型声明绝不会实际的被这样替换。没有代码的多个拷贝,源码中没有、二进制代码中也没有;磁盘中没有,内存中也没有。如果你是一个C++程序员,你会理解这是和C++模板的很大的区别。

一个泛型类型的声明只被编译一次,并且得到一个class文件,就像普通的class或者interface的声明一样。

类型参数就跟在方法或构造函数中普通的参数一样。就像一个方法有形式参数(formal value parameters)来描述它操作的参数的种类一样,一个泛型声明也有形式类型参数(formal type parameters)。当一个方法被调用,实参(actual arguments)替换形参,方法体被执行。当一个泛型声明被调用,实际类型参数(actual type arguments)取代形式类型参数。

一个命名的习惯:我们推荐你用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母,这使它和其他的普通的形式参数很容易被区分开来。许多容器类型使用E作为其中元素的类型,就像上面举的例子。在后面的例子中还会有一些其他的命名习惯。

3. 泛型和子类继承

让我们测试一下我们对泛型的理解。下面的代码片断合法么?

List<String> ls = new ArrayList<String>(); //1

List<Object> lo = ls; //2

1行当然合法,但是这个问题的狡猾之处在于第2行。

这产生一个问题:

一个StringList是一个ObjectList么?大多数人的直觉是回答:当然!

好,在看下面的几行:

lo.add(new Object()); // 3

String s = ls.get(0); // 4: 试图把Object赋值给String

这里,我们使用lo指向ls。我们通过lo来访问ls,一个Stringlist。我们可以插入任意对象进去。结果是ls中保存的不再是String。当我们试图从中取出元素的时候,会得到意外的结果。

java编译器当然会阻止这种情况的发生。第2行会导致一个编译错误。

总之,如果FooBar的一个子类型(类或者子接口),而G是某种泛型声明,那么G<Foo>G<Bar>的子类型并不成立!!

这可能是你学习泛型中最难理解的部分,因为它和你的直觉相反。

这种直觉的问题在于它假定这个集合不改变。我们的直觉认为这些东西都不可改变。

举例来说,如果一个交通部(DMV)提供一个驾驶员里表给人口普查局,这似乎很合理。我们想,一个List<Driver>是一个List<Person>,假定DriverPerson的子类型。实际上,我们传递的是一个驾驶员注册的拷贝。然而,人口普查局可能往驾驶员list中加入其他人,这破坏了交通部的记录。

为了处理这种情况,考虑一些更灵活的泛型类型很有用。到现在为止我们看到的规则限制比较大。

4. 通配符(Wildcards)

考虑写一个例程来打印一个集合(Collection)中的所有元素。下面是在老的语言中你可能写的代码:

void printCollection(Collection c) {

Iterator i = c.iterator();

for (int k = 0; k < c.size(); k++) {

System.out.println(i.next());

}

}

下面是一个使用泛型的幼稚的尝试(使用了新的循环语法):

void printCollection(Collection<Object> c) {

for (Object e : c) {

System.out.println(e);

}

}

问题是新版本的用处比老版本小多了。老版本的代码可以使用任何类型的collection作为参数,而新版本则只能使用Collection<Object>,我们刚才阐述了,它不是所有类型的collections的父类。

那么什么是各种collections父类呢?它写作: Collection<?>(发音为:"collection of unknown"),就是,一个集合,它的元素类型可以匹配任何类型。显然,它被称为通配符。我们可以写:

void printCollection(Collection<?> c) {

for (Object e : c) {

System.out.println(e);

}

}

现在,我们可以使用任何类型的collection来调用它。注意,我们仍然可以读取c中的元素,其类型是Object。这永远是安全的,因为不管collection的真实类型是什么,它包含的都是objects。但是将任意元素加入到其中不是类型安全的:

Collection<?> c = new ArrayList<String>();

c.add(new Object()); // 编译时错误

因为我们不知道c的元素类型,我们不能向其中添加对象。

add方法有类型参数E作为集合的元素类型。我们传给add的任何参数都必须是一个未知类型的子类。因为我们不知道那是什么类型,所以我们无法传任何东西进去。唯一的例外是null,它是所有类型的成员。

另一方面,我们可以调用get()方法并使用其返回值。返回值是一个未知的类型,但是我们知道,它总是一个Object,因此把get的返回值赋值给一个Object类型的对象或者放在任何希望是Object类型的地方是安全的。

4.1. 有限制的通配符(Bounded Wildcards)

考虑一个简单的画图程序,它可以用来画各种形状,比如矩形和圆形。

为了在程序中表示这些形状,你可以定义下面的类继承结构:

public abstract class Shape {

public abstract void draw(Canvas c);

}

public class Circle extends Shape {

private int x, y, radius;

public void draw(Canvas c) { // ...

background: white 0% 50%; color: black;

分享到:
评论

相关推荐

    Java1.5泛型指南中文版(Java1.5Gene....pdf

    Java 1.5 泛型指南中文版 本资源为 Java 1.5 泛型指南中文版的详细笔记,涵盖了泛型的基础知识、泛型类、泛型方法、通配符、擦除和翻译、类型安全、类型参数、实际类型参数、擦除、翻译、转型和 instanceof、数组、...

    Java1.5泛型指南中文版

    根据给定的信息,我们可以深入探讨Java 1.5中引入的泛型概念及其应用。...以上就是基于给定文件信息对Java 1.5泛型指南的主要知识点的详细介绍。希望这些信息能帮助读者更好地理解和应用Java中的泛型概念。

    Java1.5泛型指南中文版.doc

    ### Java 1.5 泛型指南中文版知识点解析 #### 1. 引言 在Java 1.5中引入的泛型是一种强大的类型安全机制,它允许开发者编写能够处理不同类型数据的类和方法,同时保持代码的类型安全性。通过使用泛型,开发者可以...

    Java1.5泛型指南

    ### Java 1.5 泛型指南:深入理解与应用 #### 一、引言:Java 1.5 泛型的重要性与背景 在Java 1.5版本中,引入了泛型(Generics)这一重要的特性,为类型安全性和代码重用性带来了革命性的改变。在此之前,开发...

    java 1.5泛型详解

    Java泛型是自Java 1.5版本引入的一项重要特性,极大地提高了代码的类型安全性和重用性。本文将深入探讨Java泛型的概念、优点、使用方式及其在实际开发中的应用。 **一、泛型的基本概念** 泛型是Java语言中的一种...

    Java泛型指南中文和英文

    本指南包含了一份Java 1.5泛型指南的中文版以及原始的英文教程,方便程序员进行对照学习。 **1. 泛型的概念** 泛型是一种在编写代码时指定类型参数的方式,允许开发者在定义类、接口和方法时声明类型约束。这使得...

    JDK1.5泛型讲解和例子

    JDK1.5泛型讲解 不错的东西 对jdk需要研究的朋友不妨看看 新手也来学习学习```

    java泛型指南 经典

    ### Java泛型指南经典知识点解析 #### 一、引言 Java 1.5 版本引入了一系列重要的语言特性,其中“泛型”是其中一项关键特性。泛型的引入极大地提高了 Java 语言的类型安全性和代码重用性。本文档旨在深入探讨 ...

    JDK1.5泛型使用下载

    Java泛型是在JDK 1.5版本中引入的一项重要特性,极大地增强了类型安全性和代码可读性。泛型允许开发者在类、接口和方法中声明类型参数,从而实现对数据类型的抽象。在泛型的帮助下,开发者可以在编译时进行类型检查...

Global site tag (gtag.js) - Google Analytics