Collections
类提供了包装对象,通过以下三种方式之一来修改标准集合类的行为:通过同步它们,使其不可修改,或通过检查添加到它们的元素的类型。这些包装器对象实现与包装对象相同的接口,并将它们的工作委托给它们。他们的目的是限制在哪些情况下进行这项工作。这些是使用保护代理的例子(参见 Gamma
,Helm
,Johnson
和 Vlissides
,Addison-Wesley
的设计模式),代理模式的一个变体,代理控制对真实主体的访问。
代理可以用不同的方式创建。在这里,它们是由工厂方法创建的,这些方法将提供的集合对象包装在实现集合接口的集合的内部类中。随后,对代理的方法调用(主要)委托给集合对象,但代理控制调用的条件:在同步包装器的情况下,所有方法调用都被委派,但代理使用同步来确保集合一次只能由一个线程访问。在不可修改和检查集合的情况下,打破代理合同的方法调用失败,抛出相应的异常。
正如我们在第 11.5
节中解释的那样,大多数框架类都不是线程安全的 - 通过设计 - 为了避免不必要的同步开销(如传统类 Vector
和 Hashtable
引起的)。 但有时您需要编程多个线程才能访问相同的集合,并且这些同步的包装由 Collections
类为这种情况提供。
有六个同步包装工厂方法,对应于集合框架的六个预 Java 6
接口。 (在 Java 6
中没有为 NavigableSet
或 NavigableMap
提供同步包装器,如果它们已经提供,那么在极少数情况下,您会选择它们而不是线程安全集合 ConcurrentSkipListSet
和 ConcurrentSkipListMap
。)
<T> Collection<T> synchronizedCollection(Collection<T> c);
<T> Set<T> synchronizedSet(Set<T> s);
<T> List<T> synchronizedList(List<T> list);
<K, V> Map<K, V> synchronizedMap(Map<K, V> m);
<T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s);
<K, V> SortedMap<K, V> synchronizedSortedMap(SortedMap<K, V> m);
提供这些同步视图的类是有条件线程安全的(参见 11.5
节); 尽管他们的每个操作都是原子操作,但您可能需要同步多个方法调用才能获得一致的行为。 特别是,迭代器必须在集合中同步的代码块中完全创建和使用; 否则,ConcurrentModificationException
结果最多只会失败。这是非常粗粒度的同步; 如果您的应用程序大量使用同步集合,则其有效并发性将大大降低。
一个不可修改的集合将抛出 UnsupportedOperationException
来响应任何尝试更改其结构或构成它的元素。当您希望允许客户端读取内部数据结构时,这会很有用。以不可修改的包装传递结构将阻止客户更改它。它不会阻止客户更改其包含的对象,如果它们是可修改的。在某些情况下,您可能必须通过为客户提供为此目的而制作的防御性副本或通过将这些对象置于不可修改的包装中来保护内部数据结构。
有六个不可修改的包装工厂方法,对应于集合框架的六个主要接口:
<T> Collection<T> unmodifiableCollection(Collection<? extends T> c)
<T> Set<T> unmodifiableSet(Set<? extends T> s)
<T> List<T> unmodifiableList(List<? extends T> list)
<K, V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m)
<T> SortedSet<T> unmodifiableSortedSet(SortedSet<? extends T> s)
<K, V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends V> m)
来自编译器的未经检查的警告是我们要特别注意避免运行时类型违规的信号。 例如,在我们将一个类型化的集合引用传递给 ungenerified
库方法后,我们无法确定它只向集合中添加了正确类型的元素。 我们可以传入一个选中的包装器,而不是失去对集合类型安全性的置信度,它将测试每个添加到集合中的元素,以获取创建时提供的类型的成员资格。8.2
节给出了这种技术的一个例子。
为主界面提供检查包装:
static <E> Collection checkedCollection(Collection<E> c, Class<E> elementType)
static <E> List checkedList(List<E> c, Class<E> elementType)
static <E> Set checkedSet(Set<E> c, Class<E> elementType)
static <E> SortedSet checkedSortedSet(SortedSet<E> c, Class<E> elementType)
static <K, V> Map checkedMap(Map<K, V> c, Class<K> keyType, Class<V> valueType)
static <K, V> SortedMap checkedSortedMap(SortedMap<K, V> c, Class<K> keyType,Class<V> valueType)