包装器实现
原文: https://docs.oracle.com/javase/tutorial/collections/implementations/wrapper.html
包装器实现将所有实际工作委托给指定的集合,但在此集合提供的功能之上添加额外的功能。对于设计模式风扇,这是装饰器模式的示例。虽然它看起来有点奇特,但它真的非常简单。
这些实现是匿名的;该库提供静态工厂方法,而不是提供公共类。所有这些实现都可以在 Collections
类中找到,它只包含静态方法。
同步包装器
同步包装器将自动同步(线程安全性)添加到任意集合。六个核心集合接口中的每一个 - Collection
, Set
, List
, Map
, SortedSet
和 SortedMap
- 有一个静态工厂方法。
public static <T> Collection<T> synchronizedCollection(Collection<T> c);
public static <T> Set<T> synchronizedSet(Set<T> s);
public static <T> List<T> synchronizedList(List<T> list);
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);
public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s);
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);
这些方法中的每一个都返回由指定集合备份的同步(线程安全)Collection
。为了保证串行访问,必须通过返回的集合完成对后备集合的所有访问。保证这一点的简单方法是不保留对支持集合的引用。使用以下技巧创建同步集合。
List<Type> list = Collections.synchronizedList(new ArrayList<Type>());
以这种方式创建的集合与正常同步的集合一样是线程安全的,例如 Vector
。
面对并发访问,用户必须在迭代时手动同步返回的集合。原因是迭代是通过对集合的多次调用来完成的,集合必须组成一个单独的原子操作。以下是迭代包装器同步集合的习惯用法。
Collection<Type> c = Collections.synchronizedCollection(myCollection);
synchronized(c) {
for (Type e : c)
foo(e);
}
如果使用显式迭代器,则必须从synchronized
块中调用iterator
方法。不遵循此建议可能会导致不确定的行为。迭代同步Map
的Collection
视图的习语是类似的。当迭代任何Collection
视图而不是在Collection
视图本身上进行同步时,用户必须在同步Map
上进行同步,如以下示例所示。
Map<KeyType, ValType> m = Collections.synchronizedMap(new HashMap<KeyType, ValType>());
...
Set<KeyType> s = m.keySet();
...
// Synchronizing on m, not s!
synchronized(m) {
while (KeyType k : s)
foo(k);
}
使用包装器实现的一个小缺点是您无法执行包装实现的任何非接口操作。因此,例如,在前面的List
示例中,您不能在包装的ArrayList
上调用ArrayList
的 ensureCapacity
操作。
不可修改的包装
与为包装集合添加功能的同步包装器不同,不可修改的包装器可以消除功能。特别是,它们通过拦截将修改集合并抛出UnsupportedOperationException
的所有操作来消除修改集合的能力。不可修改的包装有两个主要用途,如下所示:
- 在构建集合后使集合不可变。在这种情况下,最好不要维护对支持集合的引用。这绝对保证了不变性。
- 允许某些客户端以只读方式访问您的数据结构。您保留对支持集合的引用,但分发对包装器的引用。通过这种方式,客户可以查看但不能修改,同时保持完全访问权限。
与同步包装器一样,六个核心Collection
接口中的每一个都有一个静态工厂方法。
public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c);
public static <T> Set<T> unmodifiableSet(Set<? extends T> s);
public static <T> List<T> unmodifiableList(List<? extends T> list);
public static <K,V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m);
public static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<? extends T> s);
public static <K,V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends V> m);
检查接口包装
Collections.checked
接口*包装器用于通用集合。这些实现返回指定集合的 动态*类型安全视图,如果客户端尝试添加错误类型的元素,则会抛出ClassCastException
。该语言中的泛型机制提供了编译时(静态)类型检查,但有可能打败这种机制。动态类型安全的视图完全消除了这种可能性。