包装器实现
包装器实现是一种将它们的实际工作委托给一个特定 对象集 的实现,它在该 对象集 所提供的功能之上又增加了额外的功能。 对design patterns(设计样式) 爱好者来说,这是一个 decorator(油漆工) 样式。虽然有点异国情调,但确实简单明了。
这些实现是匿名的:不是提供一个公共类,JDK 提供一个 static factory method(静态方法)。 所有这些都可以在仅包含静态方法的Collections API 中找到。
同步包装器(Synchronization Wrappers)
同步包装器将自动同步(线程安全的)添加到一个任意的 对象集。6个 核心 对象集 接口中的每一个都对应一个静态方法:
public static Collection synchronizedCollection(Collection c);
public static Set synchronizedSet(Set s);
public static List synchronizedList(List list);
public static Map synchronizedMap(Map m);
public static SortedSet synchronizedSortedSet(SortedSet s);
public static SortedMap synchronizedSortedMap(SortedMap m);每一个这样的方法都返回一个由特定 对象集 作为后备的同步(线程安全的)Collection。 为保证串行存取,所有对后备 对象集 的存取都必须通过返回的 对象集 来完成,这一点是至关重要的。 保证这一点的一个简便办法是不要保持对后备 对象集 的引用, 创建这样的同步 对象集 是一个小技巧:
List list = Collections.synchronizedList(new ArrayList());
一个用这种方式创建的对象集,每一比特都是线程安全的,就象VectorM那样的"正常"同步 对象集 一样。 在需要并发存取情况下,在返回的 对象集 上迭代时,用户对返回的 对象集 做手工同步是十分必要的。 这是因为迭代是通过对对象集 的多重调用完成的,它必须被编写为一个单独的最小单元操作(atomic operation)。在一个包装器同步的 对象集 上的迭代惯用程序如下所示:
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APICollection c = Collections.synchronizedCollection(myCollection);
synchronized(c) {
Iterator i = c.iterator(); // Must be in the synchronized block!
while (i.hasNext())
foo(i.next());
}在一个同步 Map 的 Collection视图上的迭代惯用程序与上述程序相似,但有一个诀窍,那就是,当在同步 Map 的Collection视图上迭代时, 用户必须对同步 Map 做手工同步,而不是对 Collection视图本身做同步:
Map m = Collections.synchronizedMap(new HashMap());
...
Set s = m.keySet(); // Needn"t be in synchronized block
...
synchronized(m) { // Synchronizing on m, not s!
Iterator i = s.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}包装器实现的一个小的缺陷是你不能执行一个包装器实现的非接口操作。因此,比如在上面的 List 的例子中,你就不能调用包装的ArrayList上的ensureCapacity 操作。
不可变包装器(Unmodifiable Wrappers)
从概念上讲,不可变包装器与同步包装器是相似的,但它要更简单。它不是在包装的 对象集 上增加功能,而是减少功能。特别是,它取消了更改 对象集 的功能;办法是截取所有那些要更改 对象集 的操作,并扔出一个UnsupportedOperationException。 不可变包装器有两个主要用途:
使一个对象集在一旦建立后就不可在改变。针对这种情况,不保持对后备 对象集 的引用是一个好的做法。它可以绝对保证不可变性。
允许"二等公民(second-class citizens)" 对你的数据结构的只读访问。你可以保持对后备 对象集 的引用,但施舍一个对包装器的引用。用这样的办法,二等公民可以看,但不能触动,而你可以保持全面的存取。
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection API就象同步包装器一样,6个核心对象集接口中的每一个接口都对应一个静态方法:
public static Collection unmodifiableCollection(Collection c);
public static Set unmodifiableSet(Set s);
public static List unmodifiableList(List list);
public static Map unmodifiableMap(Map m);
public static SortedSet unmodifiableSortedSet(SortedSet s);
public static SortedMap unmodifiableSortedMap(SortedMap m);便利实现(Convenience Implementations)
这一节将描述几个小型实现。当你不需要一个通用实现的全部功能时,使用小型实现更方便,效率更高。这一节描述的所有实现都可通过静态方法获得,或者通过输出常数(不是公共类)来获得。
数组的List视图
Arrays.asList方法返回它的数组参数的一个 List视图。List 变化会写在数组上,反之亦然。 对象集 的大小就是数组的大小,且不能被改变。如果在该 List 上调用了 add 或 remove 方法,则回导致一个UnsupportedOperationException 。
正常地使用这个实现就象在基于数组的API和基于 对象集 的API之间架起了一座桥梁。 它允许你将一个数组传递给期望一个 Collection 或一个 List 的方法。然而,这个实现还有另一个用途。如果你需要一个定尺寸 List, 它将比任何通用 List 实现的效率都高。以下是一个惯用程序:
List l = Arrays.asList(new Object[size]);
注意对一个后备数组的引用是不保留的。
不可变多重-拷贝List(Immutable Multiple-Copy List) 偶尔你需要一个不可变的由相同元素的多个拷贝所组成的 List 。Collections.nCopies方法可返回这样的一个 List。这个实现有两个用途。一个是初始化一个新创建的 List。例如,假设你要初始化一个 ArrayList,使之包含 1000 个空元素。 请看如下咒语:
关键字: Java脚本 Java SE 6 XQuery查询 Web服务 Collections API Reflection APIList l = new ArrayList(Collections.nCopies(1000, null));
当然,每个元素的初始值不必是空。第二个主要用途是增长一个现存 List。例如,假设你要将串 fruit bat 的69个拷贝添加到一个 List 的末尾。不知道你为什么要这样做,我们只假设你是要这样做。下面是你应采用的做法:
lovablePets.addAll(Collections.nCopies(69, "fruit bat"));
通过使用 addAll(同时采用索引和一个 Collection作参数), 你可以将新的元素添加到一个 List 的中间,而不是末尾。
不可变单元素Set(Immutable Singleton Set)
有时你需要一个不可变的单元素 Set, 它由一个单一的特定元素所构成。Collections.singleton 方法可返回这样一个 Set。这个实现的一个用途是以下这个惯用程序所表达的,它从一个 Collection中删除了一个特定元素的所有具体值:
c.removeAll(Collections.singleton(e));
有一个相关的惯用程序,它从一个 Map 中删除映射一个特定值的所有元素。例如,假设你有一个称为 profession 的 Map ,他将人与他们所从事的工作相映射。假使你要删除所有的律师,下面的程序可以完成这件事:
profession.values().removeAll(Collections.singleton(LAWYER));
这个实现的另一个用途是为接受Collection的方法提供一个单一输入值。
空Set和空List常数
Collections 类提供两个常数,用以表示空 Set 和空 List, 它们是Collections.EMPTY_SET和Collections.EMPTY_LIST。 不清楚这两个常数作为实现是否真的有资格,但本课程似乎是提及它们的最合适的地方。这两个常数的主要用途是在你不想提供任何值时,将它们传给需要Collection型参数的方法