Arrays.sort() 是 Java 中一个非常核心且常用的方法,它位于 java.util.Arrays 类中,用于对各种类型的数组进行排序,它的强大之处在于提供了多种重载形式,能够处理基本类型数组和对象数组,并且对于对象数组,它支持自定义排序规则。
基本概述
Arrays.sort() 方法的主要功能是对数组进行原地排序,这意味着它会直接修改传入的数组,而不是返回一个新的已排序的数组。
它的核心功能依赖于两种不同的排序算法:
- 基本类型数组:使用双轴快速排序,这是一种优化的快速排序算法,平均时间复杂度为 O(n log n),并且在大多数情况下性能非常出色。
- 对象数组:使用归并排序 的优化版本,称为 TimSort,TimSort 是一种混合排序算法,结合了归并排序的稳定性和插入排序对小数据集的高效性,它的时间复杂度也是 O(n log n),并且是稳定排序。
稳定排序:如果两个元素相等,它们在排序后的相对顺序与排序前保持一致。 不稳定排序:不保证相等元素的相对顺序。
方法签名与重载
Arrays.sort() 提供了非常丰富的重载形式,主要可以分为以下几类:
a. 对基本类型数组进行排序
这是最简单的用法,直接对数组元素进行升序排序。
// 语法
Arrays.sort(primitiveArray);
// 示例
import java.util.Arrays;
public class PrimitiveSortExample {
public static void main(String[] args) {
int[] numbers = {5, 1, 9, 3, 7, 2, 8, 4, 6};
System.out.println("排序前: " + Arrays.toString(numbers));
Arrays.sort(numbers); // 对 int 数组进行升序排序
System.out.println("排序后: " + Arrays.toString(numbers));
}
}
// 输出:
// 排序前: [5, 1, 9, 3, 7, 2, 8, 4, 6]
// 排序后: [1, 2, 3, 4, 5, 6, 7, 8, 9]
支持的基本类型包括:int, long, short, byte, char, double, float, boolean (false 排在 true 前面)。
b. 对对象数组进行排序
当数组元素是对象时,Arrays.sort() 会要求这些对象必须实现 Comparable 接口。Comparable 接口定义了对象之间“自然排序”的规则。
// 语法
Arrays.sort(objectArray);
// 示例: 对 String 数组排序
// String 类已经实现了 Comparable<String> 接口
import java.util.Arrays;
public class ObjectSortExample {
public static void main(String[] args) {
String[] names = {"Charlie", "Alice", "David", "Bob"};
System.out.println("排序前: " + Arrays.toString(names));
Arrays.sort(names); // 按照字典序(自然顺序)排序
System.out.println("排序后: " + Arrays.toString(names));
}
}
// 输出:
// 排序前: [Charlie, Alice, David, Bob]
// 排序后: [Alice, Bob, Charlie, David]
如果尝试对一个没有实现 Comparable 接口的自定义对象数组调用 Arrays.sort(),程序会抛出 ClassCastException。
class Person {
String name;
int age;
// ... constructor, getters, setters
}
// Person 类没有实现 Comparable
Person[] people = {new Person("Alice", 30), new Person("Bob", 25)};
Arrays.sort(people); // 运行时抛出 ClassCastException
c. 对数组的指定范围进行排序
你可以只对数组的一部分进行排序,而保持其他部分不变。
// 语法
Arrays.sort(array, fromIndex, toIndex);
// 示例
import java.util.Arrays;
public class RangeSortExample {
public static void main(String[] args) {
int[] numbers = {5, 1, 9, 3, 7, 2, 8, 4, 6};
System.out.println("排序前: " + Arrays.toString(numbers));
// 对索引 2 到 6 (包含2, 不包含6) 的元素进行排序
// 即对子数组 {9, 3, 7, 2} 进行排序
Arrays.sort(numbers, 2, 6);
System.out.println("排序后: " + Arrays.toString(numbers));
}
}
// 输出:
// 排序前: [5, 1, 9, 3, 7, 2, 8, 4, 6]
// 排序后: [5, 1, 2, 3, 7, 9, 8, 4, 6]
注意:
fromIndex是包含的,toIndex是不包含的。
d. 使用自定义比较器进行排序
这是 Arrays.sort() 最强大的功能之一,当你需要自定义排序规则时,可以使用 Comparator 接口。
- 用于对象数组:
// 语法
Arrays.sort(objectArray, comparator);
// 示例: 对 Person 对象数组按年龄排序
import java.util.Arrays;
import java.util.Comparator;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
public class ComparatorSortExample {
public static void main(String[] args) {
Person[] people = {
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35)
};
System.out.println("按年龄升序排序前: " + Arrays.toString(people));
// 使用 lambda 表达式创建 Comparator
Arrays.sort(people, Comparator.comparingInt(p -> p.age));
System.out.println("按年龄升序排序后: " + Arrays.toString(people));
// 按姓名降序排序
Arrays.sort(people, Comparator.comparing(Person::getName).reversed());
System.out.println("按姓名降序排序后: " + Arrays.toString(people));
}
}
// 输出:
// 按年龄升序排序前: [Alice(30), Bob(25), Charlie(35)]
// 按年龄升序排序后: [Bob(25), Alice(30), Charlie(35)]
// 按姓名降序排序后: [Charlie(35), Bob(25), Alice(30)]
-
用于基本类型数组 (Java 8+): 虽然不能直接为基本类型数组传递
Comparator,但可以使用IntStream,LongStream等进行转换和排序。import java.util.Arrays; import java.util.Comparator; public class PrimitiveComparatorExample { public static void main(String[] args) { int[] numbers = {5, 1, 9, 3, 7, 2, 8, 4, 6}; System.out.println("排序前: " + Arrays.toString(numbers)); // 使用 IntStream 进行自定义排序(按数字的相反数排序) // 先转为 Integer 数组,因为 Comparator 不支持基本类型 Integer[] boxedNumbers = Arrays.stream(numbers).boxed().toArray(Integer[]::new); Arrays.sort(boxedNumbers, Comparator.comparingInt(i -> -i)); // 再转回基本类型数组 Arrays.setAll(numbers, i -> boxedNumbers[i]); System.out.println("按相反数排序后: " + Arrays.toString(numbers)); } } // 输出: // 排序前: [5, 1, 9, 3, 7, 2, 8, 4, 6] // 按相反数排序后: [9, 8, 7, 6, 5, 4, 3, 2, 1]
深入理解:Comparable vs. Comparator
这是一个非常重要的概念,也是面试中的高频考点。
| 特性 | Comparable |
Comparator |
|---|---|---|
| 位置 | 在类内部实现 | 在类外部创建,是一个独立的类/函数 |
| 目的 | 定义类的“自然排序”规则 | 定义“临时/自定义”的排序规则 |
| 方法 | int compareTo(T o) |
int compare(T o1, T o2) |
| 使用方式 | Arrays.sort(myObjectArray); |
Arrays.sort(myObjectArray, myComparator); |
| 修改 | 需要修改源类的代码 | 不需要修改源类,非常灵活 |
| 数量 | 一个类只能有一个 compareTo 方法 |
可以创建任意数量的 Comparator 来实现不同排序 |
选择建议:
- 如果一个类有一个非常明确、主要的排序方式(
String按字典序,Date按时间),让它实现Comparable接口。 - 如果排序规则是多种多样的、临时的,或者你不想/不能修改源类的代码,那么使用
Comparator。Comparator更加灵活和强大。
性能与注意事项
-
时间复杂度:对于大多数情况,
Arrays.sort()的时间复杂度为 O(n log n),这是比较高效的排序算法。 -
空间复杂度:
- 基本类型的双轴快速排序是原地排序,空间复杂度为 O(log n)(主要是递归栈空间)。
- 对象数组的 TimSort 需要额外的临时空间,空间复杂度为 O(n)。
-
稳定性:对象数组的排序是稳定的,而基本类型数组的排序是不稳定的,在需要稳定排序的场景下,务必使用对象数组。
-
NullPointerException:如果数组中包含null值,调用Arrays.sort()会抛出NullPointerException,在排序前,你需要确保数组中没有null,或者使用Comparator来处理null值。// 处理 null 值的 Comparator Comparator<String> nullSafeComparator = Comparator.nullsFirst(Comparator.naturalOrder()); String[] arrayWithNull = {"apple", null, "banana", "cherry"}; Arrays.sort(arrayWithNull, nullSafeComparator); // 结果: [null, apple, banana, cherry]
Java 8+ 的新特性:Arrays.parallelSort()
从 Java 8 开始,Arrays 类引入了 parallelSort() 方法,它的行为与 sort() 基本相同,但会利用多核处理器的并行能力来加速排序过程。
- 适用场景:对于非常大的数组(元素数量超过 10,000),
parallelSort()可能会比sort()更快。 - 实现原理:它会将数组分成多个段,每个段在不同的 CPU 核心上进行排序,最后再将这些已排序的段合并。
- 小数组:对于小数组,并行排序的开销(线程创建和任务分配)可能比串行排序还要大,因此性能可能更差。
// 语法与 sort() 类似 Arrays.parallelSort(array); Arrays.parallelSort(array, fromIndex, toIndex); Arrays.parallelSort(array, comparator);
| 特性 | Arrays.sort() |
|---|---|
| 核心功能 | 对数组进行原地排序 |
| 算法 | 基本类型: 双轴快速排序 (O(n log n), 不稳定) 对象: TimSort (O(n log n), 稳定) |
| 重载形式 | 基本类型排序 2. 对象排序 (需 Comparable) 3. 范围排序 4. 自定义排序 (需 Comparator) |
| 关键接口 | Comparable (自然排序), Comparator (自定义排序) |
| 现代替代 | Arrays.parallelSort() (适用于大数据集,利用多线程) |
| 注意事项 | 对象数组不能包含 null;基本类型排序不稳定 |
掌握 Arrays.sort() 的各种用法是 Java 开发者的基本功,理解其背后的原理和 Comparable/Comparator 的区别,能让你写出更灵活、更高效的代码。
