collections工具类提供的unmodifiable不可变封装

Java 中 Collections.unmodifiableXXX 系列方法(如 unmodifiableList、unmodifiableMap、unmodifiableSet)并不是真正创建新集合,而是返回一个不可变视图——底层仍指向原集合,只是拦截所有修改操作并抛出 UnsupportedOperationException。

它只防“直接修改”,不防“间接变更”

封装后的不可变集合本身不能调用 add、put、clear 等方法,但若原始集合被其他引用修改,视图会同步反映变化:

原集合是可变的,且仍有其他引用指向它 → 不可变视图可能“意外改变” 例如:List<String> list = new ArrayList<>(Arrays.asList("a")); List<String> unmod = Collections.unmodifiableList(list); list.add("b"); → 此时 unmod 的大小变成 2,遍历时也会看到 “b” 要真正隔离,需先深拷贝或使用不可变实现(如 ImmutableList.copyOf() 来自 Guava,或 Java 10+ 的 List.of())

所有嵌套对象仍是可变的

不可变封装只作用于集合结构本身,不递归冻结元素:

unmodifiableList 中的 Person 对象,其字段仍可被修改(如 person.setName("new")) 若需完全不可变,元素类型也需是不可变类(如 String、LocalDate),或手动确保其状态封闭

线程安全 ≠ 不可变

unmodifiable 视图不是线程安全的“快照”:

它不保证迭代过程中的并发一致性;若原集合正被另一线程修改,遍历可能抛 ConcurrentModificationException(取决于原集合类型) 如原集合是 ArrayList,即使包装成 unmodifiable,多线程读写仍需额外同步 真需要线程安全的只读访问,推荐用 Collections.synchronizedList + 显式同步,或选用 CopyOnWriteArrayList 等并发集合

替代方案更推荐现代写法

JDK 9+ 提供了更清晰、真正不可变的工厂方法:

List.of("a", "b")、Set.of(1, 2)、Map.of("k", "v") —— 返回的是紧凑、高效、不可序列化、空值敏感的不可变实例 它们不依赖原集合,也不允许 null 元素(除 Map.ofEntries() 等少数例外),语义更明确 对已有集合转不可变,可用 List.copyOf(existingList)(JDK 10+),它会做防御性拷贝,彻底切断与原集合联系

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。