Collections.unmodifiableNavigableSet返回的是共享底层结构的不可修改视图,仅拦截顶层修改操作,不复制数据、不冻结元素状态、不保证线程安全,原始集合变更会实时反映在视图中。

Collections.unmodifiableNavigableSet 返回的是一个不可修改的视图,不是新集合,它本身不复制数据,只拦截修改操作。
只读边界止于顶层结构
该方法仅冻结对 NavigableSet 本身的增删改操作(如 add、remove、clear),以及通过其子集视图(headSet、tailSet、subSet)或迭代器发起的修改。但底层原始 NavigableSet 若被其他代码修改,变化会立即反映在不可变视图中——因为两者共享同一内部结构。
- 调用 unmodifiableNavigableSet(s) 后,若有人仍持有原始 s 引用并执行 s.remove(x),视图中也会丢失该元素
- 视图的 size()、contains()、first()、floor() 等查询方法全部“穿透”到原集合执行
- 所有子集(如 tailSet(5))返回的也是不可修改视图,但它们同样依赖原始集合状态
嵌套可变对象不受保护
如果 NavigableSet 中的元素本身是可变对象(例如 StringBuilder、自定义含 public 字段的类),unmodifiableNavigableSet 完全不干预这些对象的内部状态变更。
- 比如 set 包含 new StringBuilder("abc"),外部仍可调用该实例的 append("def")
- 视图无法感知也不阻止这种修改,除非元素类型本身设计为不可变(如 String、Integer)
序列化与线程安全不自动继承
返回的不可变视图是否可序列化,完全取决于传入的原始 NavigableSet 是否可序列化;它本身不提供线程安全保证。
立即学习“Java免费学习笔记(深入)”;
- 即使原始 set 是 ConcurrentSkipListSet,unmodifiableNavigableSet 视图也不额外加锁
- 多线程并发读取安全(无写操作),但若原始集合正被其他线程修改,视图可能看到中间态或抛出 ConcurrentModificationException
- 序列化后反序列化得到的是新实例,但内容仍与原始集合当时状态一致,不带“冻结快照”语义
替代方案:真正隔离需主动复制
若需要与原始集合彻底解耦,必须显式创建独立副本,再包装为不可变视图。
- 推荐方式:new TreeSet(originalSet) → Collections.unmodifiableNavigableSet(treeSet)
- Java 12+ 可用 NavigableSet.copyOf(originalSet),它会构造新 TreeSet 并返回不可变视图(注意:copyOf 不接受 null 元素)
- 避免直接包装已有 TreeSet 实例,除非确认该实例不再被任何其他代码修改


















