基本类型排序用双轴快排,因无需稳定性且性能更优;对象数组用TimSort,因需稳定性且适应真实数据局部有序性;JDK硬编码分发,不可手动切换。

基本类型排序不需要稳定性,双轴快排更合适
基本类型(如 int[]、double[])没有身份标识,两个值相等的 5 完全不可区分,排序后谁在前谁在后无关业务逻辑。因此 JDK 完全可以舍弃稳定性,换取更快的平均性能和更低的空间开销。
双轴快排(DualPivotQuicksort)在随机数据、含重复元素或部分有序数据上表现更均衡:它把数组一次划分为三段(p1、∈[p1,p2]、> p2),减少递归深度,也更利于 CPU 缓存局部性。实测比较次数比单轴快排少约 5%,交换也更少。
- 原地排序,仅需
O(log n)栈空间(递归深度) - 对极小数组(长度 ≤ 47)自动切回插入排序,避免递归开销
- 重复元素优化:连续相等段直接跳过,不反复比较
对象数组必须稳定,TimSort 是现实数据的最优解
对象(如 String[]、Person[])有业务身份。比如按分数排序学生列表时,两个同分学生应保持原始录入顺序——这就是稳定性要求。而快排天然不稳定,无法满足。
TimSort 是 Python 引入、Java 7 起 adopted 的混合算法:先识别已有序的“run”(最小长度为 32),对短 run 用二分插入排序,再逐层归并。它在真实数据中极高效,因为日志、时间序列、用户输入等常自带局部有序性。
- 最坏/平均时间复杂度都是
O(n log n),但最优情况可达O(n)(完全有序时只扫描一遍) - 需要
O(n)额外临时空间,这是稳定归并类算法的固有代价 - 比较开销更低:对象比较涉及方法调用(
compareTo()或compare()),TimSort减少比较次数的优势比快排更明显
你不能手动切换算法,但能绕过限制
JDK 硬编码了类型分发逻辑:Arrays.sort(int[]) 永远走双轴快排,Arrays.sort(Integer[]) 永远走 TimSort。没有配置项、系统属性或反射方式能强制改变它。
若真遇到性能瓶颈且确定可牺牲稳定性(比如你只是临时去重或打乱后统计),可行路径只有两条:
- 把
Integer[]拆箱成int[]再排序(注意null值会 NPE) - 自己实现一个不稳定的快排(但大概率不如 JDK 的
DualPivotQuicksort细节优化)
绝大多数业务场景下,这种绕行得不偿失——JDK 的选择已经覆盖了性能、稳定性、内存与真实数据特征的综合权衡。
排查慢排序时,别怪算法,先看数据特征
如果发现 Arrays.sort() 异常慢,大概率不是算法本身的问题。双轴快排和 TimSort 都经过海量场景打磨。真正该检查的是:
- 对象数组是否在
compareTo()里做了耗时操作(如 IO、正则匹配、数据库查询) - 基本类型数组是否含大量重复值且恰好触发了某些 pivot 退化路径(极少见,但可用
-XX:MaxJavaStackTraceDepth=1看栈深) - 是否误将大对象数组传给
Arrays.sort(),却忘了它需要O(n)额外空间,引发频繁 GC
算法选型是静态的,但它的实际表现高度依赖你传进去的数据和比较逻辑——这才是最容易被忽略、也最常出问题的地方。










