Collections.unmodifiableCollection()仅拦截集合接口的修改操作,不防护可变元素内部状态或底层引用变更;需确保传入前元素不可变或已深拷贝,并配合对应类型方法(如unmodifiableList)及额外包装子视图。

为什么 Collections.unmodifiableCollection() 不能直接防住所有修改?
它只拦截对集合对象本身的操作(比如 add()、remove()、clear()),但不保护元素内部状态。如果集合里存的是可变对象(如 ArrayList、自定义的 POJO),调用方仍能通过引用修改元素内容,比如 list.get(0).setName("xxx") —— 这种修改完全绕过只读包装。
怎么正确使用 Collections.unmodifiableCollection()?
关键在「传入前确保元素不可变」。常见做法:
- 只往里面放不可变类型:如
String、Integer、LocalDateTime,或你自己写的final字段 + 无 setter 的类 - 如果必须放可变对象,先做深拷贝再包装,例如用
new ArrayList(original)创建副本,再传给unmodifiableCollection() - 注意返回类型:它返回的是
Collection接口,不是具体实现类;如果下游需要List特有方法(如get(int)),得用Collections.unmodifiableList()等对应方法
unmodifiableCollection() 和 unmodifiableList() 有什么区别?
前者只保证基础集合接口行为只读,后者额外支持 List 接口方法(如随机访问、subList())也受保护。但重点是:subList() 返回的子视图默认仍是可修改的 —— 即使原 List 已被 unmodifiableList() 包装,你也得对子视图再套一层:
List<String> original = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> unmod = Collections.unmodifiableList(original);
List<String> sub = unmod.subList(0, 2); // ❌ 这个 sub 仍是可修改的!
List<String> safeSub = Collections.unmodifiableList(sub); // ✅ 必须再包一次
容易忽略的坑:包装后仍可能被反射或序列化破坏
它只是基于运行时方法拦截,不提供内存级防护。反射可以绕过访问控制修改底层 collection 字段;反序列化时若未重写 readObject(),也可能重建出可变实例。真正高安全场景(如权限敏感模块),应配合不可变数据结构(如 ImmutableList from Guava)或手动封装防御逻辑。

















