怎么利用 Collections.unmodifiableNavigableMap() 创建一个完全只读且支持范围导航的映射
想要一个真正只读、同时还能玩转子视图(subMap、headMap)的 Na vigableMap?关键不在 Collections.unmodifiableNa vigableMap() 本身——它只是个包装器,真正需要你提前准备好一个底层的 Na vigableMap,比如 TreeMap。说白
想要一个真正只读、同时还能玩转子视图(subMap、headMap)的 Na vigableMap?关键不在 Collections.unmodifiableNa vigableMap() 本身——它只是个包装器,真正需要你提前准备好一个底层的 Na vigableMap,比如 TreeMap。说白了,你得先搭好骨架,再给它穿上“只读铠甲”。
1. 必须基于可导航的底层实现
这个方法要求参数必须是 Na vigableMap 类型,你别想着传个 HashMap 或者 SortedMap 就能蒙混过关——它不吃这套。最靠谱的选择就是 TreeMap。用的时候注意几个小坑:键类型要么实现 Comparable,要么你显式传一个 Comparator;别塞 null 键,TreeMap 天生拒绝这个;还有最关键的一点:初始化后立刻包装,别让外部代码还捏着原始 TreeMap 的引用——否则你穿的铠甲就是纸糊的。
2. 正确创建只读视图的步骤
三步走,一步都不能少:
- 新建一个
TreeMap,把数据填进去。 - 调用
Collections.unmodifiableNa vigableMap()给它套上只读外壳。 - 扔掉原始
TreeMap的引用,只保留返回的只读视图。
看看示范代码:
Na vigableMapmutable = new TreeMap<>(); mutable.put("apple", 1); mutable.put("banana", 2); mutable.put("cherry", 3); // ✅ 正确:立刻包装并赋值给 final 变量 final Na vigableMap readOnly = Collections.unmodifiableNa vigableMap(mutable); // ❌ 危险:还留着 mutable 引用,别人仍可修改底层
看到没?final 关键字只是锦上添花,真正保险的是把 mutable 那根线剪断——比如让它在创建后立即出作用域。
3. 范围导航能力完全保留
包装后的视图依然保留 Na vigableMap 的所有范围操作,但任何想修改的方法——比如 put、remove、甚至 subMap 的可变重载——都会毫不犹豫地抛 UnsupportedOperationException。这防护做得挺绝的:
readOnly.subMap("a", true, "c", false)返回的也是只读子视图。readOnly.headMap("banana", true)同样只读。- 连
readOnly.descendingMap()倒序视图都继承了只读血统。
注意:这些子视图和逆序视图本身并不是重新包装的,它们共享同一层防护逻辑——相当于整个家族都穿了同款铠甲。
4. 安全边界提醒
别看它叫“只读”,这个特性其实只是运行时防护,不是编译期约束:
- 如果原始
TreeMap的引用没被销毁,别人依然能暗地里修改它,导致你看到的只读视图内容悄然变脸。 - 反射或序列化攻击?它挡不住。它只防御常规 API 调用。
- 如果你需要深度不可变(比如值对象本身也不可变),记得额外保证 value 类型也是不可变的——光靠包装可不够。



































