Chinaunix首页 | 论坛 | 博客
  • 博客访问: 400297
  • 博文数量: 38
  • 博客积分: 1490
  • 博客等级: 上尉
  • 技术积分: 406
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-08 00:52
文章分类

全部博文(38)

文章存档

2014年(1)

2013年(1)

2008年(6)

2007年(7)

2006年(23)

我的朋友

分类: Java

2007-05-20 11:23:40

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

英文版pdf下载链接:

                                译者:  

       

(第七部分)

 原文地址http://blog.csdn.net/explorers/archive/2005/08/15/454837.aspx

 

前面,我们讲述了新老代码如何交互。现在,是时候研究更难的泛型化老代码的问题了。

如果你决定把老代码转换成使用泛型的代码,你需要仔细考虑怎么修改你的API

你必须确定泛型化的API不会过分严格,它必须继续支持原来的API调用契约(original contract of the API)。在考虑几个 java.util.Collection中的例子。泛型代码之前的API像:

interface Collection {

public boolean containsAll(Collection c);

public boolean addAll(Collection c);

}

一个稚嫩的泛型化尝试:

interface Collection<E> {

public boolean containsAll(Collection<E> c);

public boolean addAll(Collection<E> c);

}

这当然是类型安全的,但是它不支持这个API的原始契约(original contract)

containsAll() 方法能对所有进来的任意类型的collection工作。它只有在传进来的collection中真正只包含E的实例才成功,但是:

l         传进来的collection的静态类型可能不同,可能是因为调用者不知道传进来的colleciton的精确类型,或者因为它是一个CollectionSE的子类型。

l         用一个不同类型的collection来调用containsAll()应该是合法的。这个例程应该能够工作,返回false

addAll(),我们应该能够添加任何元素是E的子类型的collection。我们已经在第5部分讲述了怎么正确的处理这种情况。

 你还应该保证修订过的API保持与老客户端的二进制兼容。者以为者APIerasure必须与老的未泛型化版本一样。在大多数情况下,这是很自然的结果,但是有些精巧的情形(subtle cases)。我们看看我们已经碰到过的精巧的情形中的一个(one of the subtle cases),方法Collections.max()。就像我们在第9部分看到的,一个似是而非的max()的方法签名是:

public static <T extends Comparable<? super T>> T max(Collection<T> coll)

这很好,除了擦除(erasure)后的签名是:

public static Comparable max(Collection coll)

这和老版本的max() 的签名不同:

public static Object max(Collection coll)

当然可以把max()定义为这个签名,但是这没有成为现实,因为所有调用了Collections.max()的老的二进制class文件依赖于返回Object的签名。

我们可以强迫the erasure不同,通过给形式类型参数T显式的定义一个父类。

public static <T extends Object & Comparable<? super T>> T max(Collection<T> coll)

这是一个对一个类型参数给定多个界限(multiple bounds)的例子,是用语法 T1 & T2 … & Tn。一个有多个界限的类型的参数是所有界限中列出来的类型的子类。当多个界限被使用的时候,界限中的第一个类型被用作这个类型参数的erasure

(原文:This is an example of giving multiple bounds for a type parameter, using the syntax T1& T2 ... & Tn. A type variable with multiple bounds is known to be a subtype of all of the types listed in the bound. When a multiple bound is used, the first type mentioned in the bound is used as the erasure of the type variable.

最后,我们应该想到max只从传进来collection中读取数据,因此它对元素是T的子类的collection可用。这给我们JDK中使用的真正的签名:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

实际中出现那么棘手的问题是很罕见的,但是专业库设计师应该准备好非常仔细的考虑转换现存的API

另一个需要小心的问题是协变式返回值(covariant returns),就是说在子类中获得一个方法的返回值(refining the return type of a method in a subclass)。在老API中你无法使用这个特性带来的好处。

为了知其原因,让我们看一个例子。

假定你的原来的API是下面的形式:

public class Foo {

public Foo create(){...}

// Factory, should create an instance of whatever class it is declared in

}

public class Bar extends Foo {

public Foo create(){...} // actually creates a Bar

}

为了使用协变式返回值的好处,你把它改成:

public class Foo {

public Foo create(){...}

// Factory, should create an instance of whatever class it is declared in

}

public class Bar extends Foo {

public Bar create(){...} // actually creates a Bar

}

现在,假定你的一个第三方客户代码:

public class Baz extends Bar {

public Foo create(){...} // actually creates a Baz

}

Java虚拟机并不直接支持不同类型返回值的方法重载。这个特性是由编译器来支持的。因此,除非Baz类被重新编译,它不会正确的重载Barcreate()方法,而且,Baz必须被修改,因为Baz的代码被拒绝,它的create的返回值不是Barcreate返回值的子类。(原文: Consequently, unless the class Baz is recompiled, it will not properly override the create() method of Bar.Furthermore, Baz will have to be modified, since the code will be rejected as written - the return type of create() in Baz is not a subtype of the return type of create() in Bar.

(译注:上面的一段话有些莫名其妙,我测试过这个例子,在jdk1.4下,三个类都编译之后改变Bar,只在jdk5下重新编译Bar,然后在jdk5下,Baz仍然能够被使用,当然那,无法使用 Baz b = baz.create();这样的代码。)

Erik Ernst, Christian Plesner Hansen, Jeff Norton, Mads Torgersen, Peter von der Ah´e and Philip Wadler contributed material to this tutorial.

Thanks to David Biesack, Bruce Chapman, David Flanagan, Neal Gafter, ¨ Orjan Petersson,Scott Seligman, Yoshiki Shibata and Kresten Krab Thorup for valuable feedback on earlier versions of this tutorial. Apologies to anyone whom I’ve forgotten.

 <全文完>

阅读(2785) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~