collections.unmodifiablexxx 是装饰器模式的典型实现,因其通过轻量级代理类持原始集合引用,拦截修改操作并抛异常,读操作委托底层,统一接口且不继承具体类型,符合装饰器核心特征。

为什么 Collections.unmodifiableXXX 是装饰器模式的典型实现
它不是“包装一个新对象”,而是用一个轻量级代理类,持有一个对原始集合的引用,并在所有修改方法(如 add、remove、clear)中直接抛出 UnsupportedOperationException。原始集合本身完全不变,行为被“拦截+重定义”,这正是装饰器模式的核心:不改变被装饰对象,只动态叠加职责(这里是“不可变性”)。
- 它没有继承原始集合类型(比如不继承
ArrayList),而是实现同一接口(如List),满足“统一接口、透明使用”原则 - 所有读操作(
get、size、iterator)全部委托给底层集合,开销几乎为零 - 写操作不是被忽略,而是明确拒绝——这是“增强语义”,不是简单转发,属于装饰器中 ConcreteDecorator 的典型行为
unmodifiableList 和 unmodifiableSet 的行为差异在哪
表面上看都是“不可修改”,但它们的装饰逻辑粒度不同:前者只拦截 List 接口定义的修改方法(add(int,E)、set(int,E) 等),后者则针对 Set 接口的方法(add、remove)。关键在于,它们各自持有的是 List 或 Set 类型引用,而非 Collection——这意味着如果你把一个 Set 传给 unmodifiableList,编译都过不去。
技术上面应用了三层结构,AJAX框架,URL重写等基础的开发。并用了动软的代码生成器及数据访问类,加进了一些自己用到的小功能,算是整理了一些自己的操作类。系统设计上面说不出用什么模式,大体设计是后台分两级分类,设置好一级之后,再设置二级并选择栏目类型,如内容,列表,上传文件,新窗口等。这样就可以生成无限多个二级分类,也就是网站栏目。对于扩展性来说,如果有新的需求可以直接加一个栏目类型并新加功能操作
- 类型安全由泛型和接口契约保障,不是靠运行时检查
- 不存在“通用不可修改装饰器”,每个
unmodifiableXXX都是针对具体接口定制的具体装饰器(UnmodifiableList、UnmodifiableSet等) - 它们都继承自同一个抽象装饰器基类
UnmodifiableCollection,复用公共逻辑(如iterator()的只读封装)
常见误用:以为返回不可修改视图就等于数据安全
这是最常踩的坑:Collections.unmodifiableList(list) 只保证你拿到的那个 List 引用不可改,但只要原始 list 引用还活着,它依然能被修改,而你的“不可修改视图”会立刻反映出这些变更——因为二者指向同一底层数组或结构。
- 它不深拷贝,也不冻结状态,只是加了一层只读门禁
- 若需真正隔离,必须配合不可变数据结构(如
ImmutableListfrom Guava)或手动复制(new ArrayList(original)再套 unmodifiable) - 如果原始集合本身是线程不安全的,那即使套了 unmodifiable,多线程并发读+原始引用写,仍可能引发
ConcurrentModificationException
和手写装饰器比,unmodifiable 系列省掉了什么
它省掉了所有“装饰器链管理”逻辑:没有抽象装饰器类让你去继承,也没有组合多个装饰器的自由度(比如你没法同时套“不可修改 + 日志记录 + 缓存”)。JDK 的实现是封闭的、单职责的、高度优化的——每个 UnmodifiableXxx 类都直接实现对应接口,内部只持一个字段 final Collection c(或 final List list),连构造函数都极度精简。
- 没有泛型擦除带来的桥接方法开销;所有方法都是直接转发或抛异常,JIT 很容易内联
- 不支持运行时动态增删装饰行为,它是“一次性装饰”,符合工具方法定位
- 你不能扩展它(类是
final),也不该继承它——它的存在意义就是“用完即弃”,不是框架扩展点









