稳定。collections.sort()在java 7+中对对象列表排序时底层调用arrays.sort(object[]),采用稳定timsort算法,保证相等元素相对位置不变;基本类型数组排序虽不稳定,但不参与collections.sort()调用链。

Java的Collections.sort()到底稳不稳定?
稳定。只要传入的List实现支持随机访问(比如ArrayList),Collections.sort()在Java 7及以后版本中,底层用的是**双轴快排(Dual-Pivot Quicksort)+ 归并排序(Timsort)混合策略**,但对Object[]数组排序时,实际调用的是Arrays.sort(Object[])——它明确保证稳定。
关键点在于:稳定性只针对**相同元素的相对位置不改变**。如果你用自定义Comparator把两个逻辑上不同的对象判为“相等”,那它们的顺序就由原始位置决定,且这个顺序会被保留。
为什么有时候看着“不稳定”?常见错因
不是算法不稳,而是你没看清比较逻辑或数据状态:
- 用了
int或long比较时写成a - b,导致整数溢出,返回值符号翻转,Comparator行为失常 —— 改用Integer.compare(a, b)或Long.compare(a, b) - 自定义
Comparator里漏了null处理,遇到null字段抛NullPointerException,排序中途失败,列表可能处于半修改状态 - 把
LinkedList传给Collections.sort():虽然能跑,但会先转成数组再排,再刷回链表,既慢又容易让人误以为“原地排序失效” - 排序前列表已被其他线程修改,或本身是未同步的并发集合(如
CopyOnWriteArrayList),排序看到的快照和你预期不一致
Collections.sort()和Arrays.sort()的区别在哪?
表面看都是排序,底层策略和稳定性保障层级不同:
无论做任何事情,都要有一定的方式方法与处理步骤。计算机程序设计比日常生活中的事务处理更具有严谨性、规范性、可行性。为了使计算机有效地解决某些问题,须将处理步骤编排好,用计算机语言组成“序列”,让计算机自动识别并执行这个用计算机语言组成的“序列”,完成预定的任务。将处理问题的步骤编排好,用计算机语言组成序列,也就是常说的编写程序。在Pascal语言中,执行每条语句都是由计算机完成相应的操作。编写Pascal程序,是利用Pasca
立即学习“Java免费学习笔记(深入)”;
-
Collections.sort(List):只接受List,内部调用list.toArray()→Arrays.sort(Object[])→ 最终走Timsort(稳定) -
Collections.sort(List, Comparator):同上,只是多传个比较器,不影响稳定性 -
Arrays.sort(int[])、Arrays.sort(double[])等基本类型重载:用双轴快排,**不稳定** —— 但这些根本不会出现在Collections.sort()调用链里 - 所以只要你没绕过
Collections.sort()直接去排基本类型数组,就不用操心“不稳”问题
真要验证稳定性?动手试比读源码快
写个带标识的简单类,插入两个“值相等但ID不同”的实例,排序后检查ID顺序:
class Item {
int value;
int id;
Item(int v, int i) { value = v; id = i; }
}
List<Item> list = Arrays.asList(new Item(1, 100), new Item(2, 200), new Item(1, 99));
Collections.sort(list, Comparator.comparingInt(i -> i.value));
// 排序后,两个value==1的Item,id为100的一定在id为99的前面(原始顺序)注意:别用System.out.println(list)草率下结论 —— 确保你打印的是item.id,而不是只看item.value;也别在IDE调试器里靠“观察变量顺序”判断,得靠代码显式断言。
最易被忽略的一点:稳定性只在单次排序内成立。如果排序后又手动改了某个元素的字段,再排一次,那“原始顺序”已经变了,别指望两次排序结果之间有可复现的相对关系。









