TreeMap 的有序性源于其底层红黑树实现,通过插入/删除时的旋转与着色动态维持二叉搜索树性质和黑高平衡,确保中序遍历为升序;键需实现 Comparable 或传入 Comparator,且不可为 null。

TreeMap 在 Java 中天然保持键的有序性,它底层基于红黑树(Red-Black Tree)实现,是一种自平衡的二叉搜索树。只要键类型实现了 Comparable 接口(如 String、Integer、LocalDate 等),或你显式传入了 Comparator,TreeMap 就会按自然顺序或自定义顺序自动维护键的升序排列。
TreeMap 的有序性从何而来
TreeMap 不是靠插入后排序,而是在每次 put()、remove() 时,通过红黑树的旋转与着色操作动态调整结构,确保:
- 左子树所有键 ≤ 当前节点键 ≤ 右子树所有键(二叉搜索树性质)
- 从根到任意叶子的路径上,黑色节点数量相同(黑高平衡)
- 没有连续两个红色节点(保证近似平衡)
这些约束让 TreeMap 能在 O(log n) 时间内完成增删查,并始终维持中序遍历结果为升序键序列。
如何确保你的键能正确排序
关键取决于键类型的可比性:
立即学习“Java免费学习笔记(深入)”;
- 若用 Integer、String、LocalDateTime 等 JDK 内置类型作键:默认按自然序(升序)排序,无需额外操作
- 若用自定义类(如 Person)作键:必须让该类实现 Comparable
,重写 compareTo() 方法 - 若不想改类源码,或需多种排序逻辑:创建 TreeMap 时传入 Comparator,例如:
new TreeMap((p1, p2) -> p1.getAge() - p2.getAge())
注意 null 键和排序冲突
TreeMap 不允许 null 键(会抛 NullPointerException),因为比较时无法对 null 调用 compareTo 或 compare 方法。另外,如果两个键通过 equals() 判断相等,但 compareTo() 返回非零值,会导致行为不一致甚至数据丢失——务必保证 compareTo 与 equals 逻辑一致(即:a.compareTo(b) == 0 ⇔ a.equals(b))。
遍历顺序就是排序顺序
TreeMap 的 keySet()、entrySet()、values() 返回的集合都按键的排序顺序迭代。例如:
- keySet().iterator() → 按键升序返回键
- descendingKeySet() → 获取降序键视图(Java 8+)
- subMap(from, to)、headMap(to)、tailMap(from) → 快速获取范围子映射
这些操作都利用红黑树的结构特性,无需额外排序开销。
基本上就这些。TreeMap 的有序不是“事后整理”,而是“边存边排”,理解红黑树的平衡机制,就能明白它为什么快且稳。










