TreeSet复用TreeMap底层结构实现排序与去重,其元素作为key存入TreeMap,value为固定PRESENT对象;排序和唯一性均由比较逻辑(Comparator或Comparable)决定,而非equals/hashCode。

TreeSet 内部确实使用 TreeMap 来实现,但它并不直接“基于 TreeMap 实现”,而是**复用 TreeMap 的底层结构来达成排序与去重**——这是理解其行为的关键。
为什么说 TreeSet 依赖 TreeMap?
TreeSet 的源码中,它持有一个私有的 TreeMap 实例(JDK 8 中为 private transient NavigableMap<e> m;</e>),所有元素都作为 key 存入该 map,value 固定为一个静态的 PRESENT 对象(如 new Object())。由于 TreeMap 要求 key 唯一且有序,TreeSet 自然继承了这两项特性。
排序逻辑由比较器或自然顺序决定
TreeSet 不自己排序,而是把排序责任委托给内部 TreeMap:
- 若构造时传入
Comparator,TreeMap 使用它比较 key; - 否则要求元素实现
Comparable,调用其compareTo()方法; - 比较结果决定红黑树节点位置,也决定了迭代顺序(升序)。
唯一性本质是 Map Key 的唯一性
TreeSet 的“不重复”不是靠额外校验,而是源于 TreeMap 的语义:
- 当添加重复元素(即
compareTo() == 0或compare() == 0)时,TreeMap 的put(key, value)会覆盖旧 value,但 key 不变; - TreeSet 将此视为“插入失败”,返回
false,集合大小不变; - 因此,两个元素是否重复,完全取决于比较逻辑是否返回 0,而非
equals()或hashCode()。
需要注意的隐含行为
正因为依赖比较结果而非 equals,可能出现违反直觉的情况:
- 若自定义类仅重写
equals()但未正确实现Comparable或提供合理Comparator,可能导致逻辑错误; - 若比较器认为 a 和 b 相等(返回 0),即使
a.equals(b) == false,TreeSet 也只保留其中一个; - 遍历 TreeSet 得到的是按比较顺序排列的元素,不是插入顺序,也不是哈希顺序。
不复杂但容易忽略:TreeSet 的“有序”和“唯一”是同一套比较机制的两个结果,理解这一点,就能避开多数陷阱。

















