Arrays.sort()对基本类型数组使用双轴快排而非单轴快排,因其采用三段划分(<p1、∈[p1,p2]、>p2)、自适应阈值切换(<47插排、47–285双轴、≥286检测后择优)及五取样中位数选轴,兼顾性能与稳定性;对象数组则因需稳定排序而改用Timsort。

调用 Arrays.sort() 对 int[]、double[] 等基本类型数组排序时,底层不是传统单轴快排,而是经过深度工程优化的 双轴快速排序(Dual-Pivot Quicksort)。它快不只是因为“用了快排”,而在于三段划分、智能阈值切换和采样选轴这三重设计协同作用。
双轴划分:一次比较,三段归位
传统快排选一个 pivot,把数组分成“小于”和“大于等于”两块;双轴快排选两个 pivot(p1 < p2),线性扫描一遍,直接划出三个确定区间:
-
左段:所有元素
< p1(稳居最小部分) -
中段:所有元素满足
p1 ≤ x ≤ p2(天然接近有序,递归开销小) -
右段:所有元素
> p2(稳居最大部分)
这种结构让每轮处理更充分——多数元素只需 1–2 次比较就能落进对应段,比单轴少一次判断;三段并行收缩也显著降低最坏情况出现概率,递归栈深度更浅。
自适应策略:长度决定算法路径
JDK 不是固定用一种算法,而是根据数组长度动态决策:
- 长度 < 47:直接走插入排序——小数组常数项极低,递归反成负担
- 长度在 47–285:启用双轴快排主流程
- 长度 ≥ 286:先检测是否“基本有序”(如已升序/降序连续段较长),若是则切到归并排序;否则继续双轴快排
这个阈值不是拍脑袋定的,而是大量真实数据集上反复 benchmark 得出的平衡点。
枢轴选取:五取样中位数法保均衡
为避免快排退化(比如已排序数组选首/尾作 pivot 导致 O(n²)),JDK 在双轴快排中采用五取样法:取数组首、四分之一、中点、四分之三、末尾共 5 个位置的元素,再取其中位数作为 p1 和 p2(确保 p1 < p2)。这样既避免随机化开销,又大幅提升划分均衡性。
为什么对象数组不用双轴快排?
因为双轴快排不稳定——相等元素的相对顺序可能改变。而 String[]、自定义对象数组默认要求稳定排序(例如按姓名排序时,同名者原始先后关系需保留)。所以 JDK 对 Object[] 使用的是 Timsort(优化版归并),虽需额外空间,但稳定且对部分有序数据极其友好。

















