collections.sort 是稳定排序,其稳定性由 comparator 或 compareto() 返回 0 的逻辑决定,仅当比较结果为 0 时才保障相等元素的原始相对顺序;内部始终调用稳定的 timsort,与 list 实现无关。

Collections.sort 是稳定排序,只要用法正确,重复元素的原始相对顺序就会保留。它不依赖你“觉得”哪些值相同,而取决于 Comparator 或 compareTo() 返回 0 的判断逻辑。
稳定性不是默认“保序”,而是由比较器定义的
所谓“相等”,Java 只看 compare(a, b) == 0 的结果。比如两个 User 对象 age 都是 25,但 id 不同:如果你的 Comparator 只比 age,那它们就被视为“相等”,排序后原来在前的那个仍排在前;如果你加了 id 比较,它们就不再被判定为相等,稳定性就不适用——因为算法根本没把它们当同一组处理。
- 只按 name 排序 → 同名用户保持插入顺序
- 按 name + id 排序 → 即使 name 相同,id 不同也会分出先后,不触发稳定性保障
- Comparator 中写 a.age - b.age 要小心整数溢出,可能让 2000000000 和 -2000000000 错误判为相等,破坏稳定性
它永远走稳定路径,和 Arrays.sort 基本类型版本无关
Collections.sort 接收的是 List,内部必然调用 list.toArray(),再传给 Arrays.sort(Object[], ...) —— 这个重载始终使用 TimSort,稳定是硬性保证。你写 Collections.sort(list, cmp),它不会、也不能去调用 Arrays.sort(int[]) 那套不稳定的快排逻辑。
- 哪怕 list 是 ArrayList、LinkedList 或 Vector,稳定性都不受影响
- LinkedList 会被先转成数组排序,再逐个写回,原始位置关系依然保留
- 别被“Arrays.sort 有不稳定版本”误导——那些版本根本进不了 Collections.sort 的调用链
验证是否真稳定?动手测比读文档更可靠
写一个带唯一 id 的简单类,插入两个字段值相同但 id 不同的实例,排序后再检查 id 顺序是否与插入一致:
- 构造 List
,添加 new Person("Alice", 30, 101) 和 new Person("Alice", 30, 102) - 用只比 name 和 age 的 Comparator 排序
- 确认 101 是否仍在 102 前面 —— 是,则稳定生效
有序性和稳定性要分开理解
有序性指最终结果按规则排好;稳定性指“并列者”的次序不变。Collections.sort 提供的是前者+后者双重保障,但前提是你的 Comparator 行为合理、无副作用、不抛异常、不依赖外部状态。
- 避免在 Comparator 里修改对象状态或访问 volatile 变量
- null 值需显式处理,否则可能抛 NullPointerException,中断排序
- 多字段排序推荐用 Comparator.comparing().thenComparing(...) 链式写法,语义清晰且不易出错











