交互操作性(Interoperability)
在本课程中,你将学习两个方面的交互操作性:
兼容性
本课程将向你演示如何使对象集与先于对象集添加到Java平台上的旧的API一起工作。
API 设计
教给你如何设计一个新的 API,使它们之间可无缝交互操作。
兼容性
设计Collection Framework 是为了保证在新的 对象集 接口 和传统的被用来表示 对象集 的类型之间的完全的交互操作性: Vector, Hashtable, array, 和Enumeration。在本节中,你将学习如何将传统的 对象集 转换为新的对象集以及相反的过程。
向上兼容性
假设你要使用一个将返回传统 对象集 的 API,同时还要使用另一个API,这个API要求对象实现JDK1.2的对象集接口。为使这两个API可以平滑地交互操作,你必须将传统的 对象集 转化为新的 对象集。幸运的是,Collection Framework 使这个工作变得十分简单。
假设旧的API 返回一个对象数组,而新的API需要一个 Collection。正象在 实现课程中所讨论的,对象集 架构 具有一个便利实现,它允许一个对象数组被当作一个 List。使用Arrays.asList, 一个数组可被传递给需要一个 Collection 或一个 List 的任意方法。 Foo[] result = oldMethod(arg);
newMethod(Arrays.asList(result));
如果旧的API 返回一个 Vector 或 Hashtable, 你就一点工作都不需要做了,因为 Vector 已被改造为实现了 List 接口,而 Hashtable 也被改造为实现了 Map。 于是,一个 Vector 可被直接传递给需要一个 Collection 或一个 List 的任意方法。
Vector result = oldMethod(arg);
newMethod(result);
类似的,一个 Hashtable 可被直接传递给需要一个 Map 的任意方法。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APIHashtable result = oldMethod(arg);
newMethod(result);
比较少见的是,一个API 返回一个 Enumeration ,它代表了一个对象的 对象集。虽然没有对将 Enumeration 转换为Collection 的直接支持,但要创建包含由Enumeration 返回的所有元素的 Collection ,也是一个简单的事情:
Enumeration e = oldMethod(arg);
List l = new ArrayList();
while (e sMoreElements())
l.add(e.nextElement());
newMethod(l);
向后兼容
假设你要使用一个将返回 "新的 对象集" 的API,同时还要使用一个需要你传递 "传统的 对象集" 的API。 为使这两个API平滑地交互操作,你必须将新的 对象集 转化为传统的对象集。 同样地,Collection Framework 使这个工作十分简单。天呀,今天是你的幸运日吧?
假设新API返回一个 Collection, 而旧的API 需要一个Object数组。你可能已经知道了,Collection 接口包含一个 toArray 方法,它明显的是为此种情况设计的:
Collection c = newMethod();
oldMethod(c.toArray());
如果旧的API 需要一个 String 数组(或某些其它类型) 而不是 Object数组,那又该怎么办呢?不要丧失希望。你只要使用 toArray 的其它形式--在输入上使用数组的形式就可以了:
Collection c = newMethod();
oldMethod((String[]) c.toArray(new String[0]));
如果旧的API 需要一个 Vector, 那么就使用手头的标准对象集构造函数好了:
Collection c = newMethod();
oldMethod(new Vector(c));
旧的 API 需要一个 Hashtable 的情况可被对等地处理:
Map m = newMethod();
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APIoldMethod(new Hashtable(m));
最后,如果旧的API 需要一个 Enumeration,你该怎么办呢?这种情况不普遍,但它确实时有发生。Collections.enumeration 方法可用来处理此中情况。这个方法是个静态方法,它采用一个Collection并返回一个在 Collection 的元素之上的 Enumeration :
Collection c = newMethod();
oldMethod(Collections.enumeration(c));
API 设计
在这个虽短但却很重要的一节里,你将学习几个简单的准则,它使你的 API 可以与所有其它的遵循这一准则的精良的 API 无缝地交互操作。实质上,这些准则正是在对象集这个勇敢者的新世界里,作为一个好公民所必需的条件。
输入参数(in-Parameters)
如果你的API包含一个需要输入一个 对象集 的方法,十分重要的一点是,你应该将相关的参数类型声明为 对象集接口类型之一。绝不使用实现类型, 它允许 对象集 在不考虑实现细节的情况下被操纵,因而会使一个基于接口的对象集架构的目标流产。
进一步讲,你应该总是使用最不特殊的有意义的类型。例如,如果可以使用 Collection,则不要使用 List 或 Set 。但并不是要你绝不使用一个 List 或一个 Set ;如果一个方法依赖于这些接口之中的某些属性,则应该使用它们。例如,Java平台的许多 algorithms 要求输入一个 List ,因为它们依赖于列表是有顺序的这样一个事实。然而作为一般法则,在输入上使用的最好类型是最一般的: Collection 和 Map。
注意: 绝不、绝不定义你自己的特别的 对象集 类并要求输入这个类的对象。如果这样做,你会失去所有 由对象集架构所提供的益处。
返回值
返回值的灵活性要比输入参数大得多。你可以返回任意类型的一个对象,用它来实现或扩展某一个 对象集 接口。 这可能是接口本身之一,或是扩展(或实现)某一个接口的某些特种类型。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection API例如,你可能想象要建立一个被称作ImageList的图象处理程序包,它返回一个新的实现了 List 的类的对象。除支持 List 操作之外,ImageList 应可以支持任意特殊应用程序操作。例如,它可能提供一个 indexImage 操作,它可以返回一个将 ImageList 中的每一个图形变成指甲盖大小,然后集中在一起的一个图象。非常值得注意的一点是,即使 API 可提供 ImageList 对象输出,它也应该接受任意 Collection (或也许是 List) 对象的输入。
从某种意义上讲,返回值应该有一个与输入参数相对的行为:最好返回最特殊的和可适用的 对象集 接口,而不是最一般的。例如,如果你十分有把握由某些方法所返回的 Map 总是一个SortedMap, 你就应该将 SortedMap 的返回类型赋予这个方法,而不是 Map。 SortedMap 对象比普通 Map 对象的建立更费时,但功能也更强大。假设你的模块已经投资了一定时间来建立一个 SortedMap, 那么最好给用户以访问增加的功能的权利。进一步讲,用户将能够将返回的对象传递给那些要求 SortedMap 的方法,以及那些接受任意 Map 的方法。
再一次提醒你,绝不、绝不定义你自己的特别的 对象集 类并提供这个类的对象作为一个返回值。如果这样做,你将会失去所有由对象集架构提供的益处 (有点似曾相识吗?)
早期API(Legacy API)
现在有许多 API ,它们定义了自己特有的对象集 类型。虽然这是不幸的,但这就是事实, 因为在Java平台的前两个主要版本中没有 对象集 架构。假设你现在拥有一个那样的API。以下是你可以作的事情。 如果可能的话,重新更改你的早期 对象集 类型以实现某一个标准 对象集 接口。这样,你返回的所有对象集 将与其它基于 对象集 的 API 平滑地交互操作。如果这是不可能的(例如,由于一个或几个先前存在的类型与标准对象集接口发生冲突), 定义一个adapter class(适配器类),它包装你的早期 对象集 对象,使其表现出一个标准 对象集 的功能 (适配器类是定制实现中的一个例子)。
如果可能的话,用新的符合输入准则的调用来重新更改你的API ,使其可以接受标准对象集接口。这样的调用可与采用早期对象集 类型的调用共同存在。如果这是不可能的,为你的早期类型提供一个构造函数或静态方法,它将使用标准接口之一的一个对象,并返回一个包含相同元素(或映射)的早期 对象集 。 这两种方式都将允许用户将任意 对象集 传递到你的 API。
Collections: 结束
你已经到达 "Collections" 课程的终点。
休息一下--来一杯热气腾腾的Java吧!