一、Arrays 类概述
Arrays 是 Java 集合框架(java.util)中一个非常实用的工具类,它提供了大量静态方法来操作数组。与普通类不同,Arrays 类的所有方法都是用 static 修饰的静态方法,这意味着我们可以直接通过类名调用这些方法,而无需先创建 Arrays 类的实例对象。
Arrays 类的主要功能包括:
- 数组排序:提供了 sort() 方法,可以对各种类型的数组进行排序
- 基本数据类型数组(如 int[]、double[]、char[] 等)
- 对象数组(如 String[] 或自定义类的对象数组)
- 数组查找:提供了 binarySearch() 方法,可以在已排序的数组中进行二分查找
- 数组填充:fill() 方法可以将数组的所有元素或指定范围内的元素设置为特定值
- 数组比较:equals() 方法可以比较两个数组是否相等
- 数组转字符串:toString() 方法可以将数组内容转换为可读的字符串形式
- 其他实用功能:如 copyOf() 复制数组、asList() 将数组转为列表等
在实际应用中,Arrays 类常用于:
- 快速初始化数组元素
- 在算法实现中对数组进行排序和查找
- 调试时查看数组内容
- 进行数组的复制和比较操作
例如:
int[] numbers = {3, 1, 4, 1, 5, 9};
Arrays.sort(numbers); // 排序
System.out.println(Arrays.toString(numbers)); // 输出排序后的数组
int index = Arrays.binarySearch(numbers, 4); // 查找元素4的位置
使用前需导入包:
import java.util.Arrays;
二、常用方法实战解析
1. 数组排序:sort()
sort()方法是Java数组操作中最常用的方法之一,它提供了多种重载形式来满足不同的排序需求。这些方法都位于java.util.Arrays类中,使用时需要先导入该包。
基本类型数组排序
基本类型数组(如int、double、float、long等)可以直接使用sort()方法进行排序:
int[] nums = {3, 1, 4, 2};
Arrays.sort(nums); // 排序后:[1, 2, 3, 4]
double[] doubles = {3.5, 1.2, 4.8};
Arrays.sort(doubles); // 排序后:[1.2, 3.5, 4.8]
排序使用的是经过优化的双轴快速排序算法(Dual-Pivot Quicksort),时间复杂度为O(n log n),对于大部分数据集都能提供良好的性能。该算法由Vladimir Yaroslavskiy在2009年提出,是Java 7之后的标准排序算法。
对象数组排序
对象数组排序有两种主要方式:
- 对象实现Comparable接口
- 传入Comparator比较器
String[] strs = {"apple", "banana", "cherry"};
// 自然排序(按字典序)
Arrays.sort(strs); // [apple, banana, cherry]
// 自定义排序(按字符串长度升序)
Arrays.sort(strs, Comparator.comparingInt(String::length));
// 自定义排序(降序)
Arrays.sort(strs, (a, b) -> b.compareTo(a)); // [cherry, banana, apple]
对于自定义对象排序,需要确保对象实现了Comparable接口或提供Comparator:
class Person implements Comparable<Person> {
String name;
int age;
@Override
public int compareTo(Person p) {
return this.age - p.age;
}
}
Person[] people = new Person[3];
// 初始化people数组...
Arrays.sort(people); // 使用Comparable实现排序
// 或者使用Comparator
Arrays.sort(people, Comparator.comparing(p -> p.name));
指定范围排序
可以对数组的指定区间进行排序,这对于只需要处理数组部分元素的情况非常有用:
int[] arr = {5, 3, 8, 2, 7};
// 只排序索引1到3的元素(左闭右开区间)
Arrays.sort(arr, 1, 4); // 结果:[5, 2, 3, 8, 7]
2. 数组查找:binarySearch()
二分查找算法要求数组必须是有序的,否则结果不可预测。该方法的时间复杂度为O(log n)。
基本用法
int[] nums = {1, 2, 3, 4, 5}; // 必须是有序数组
int index = Arrays.binarySearch(nums, 3); // 返回2(找到的位置)
int notFound = Arrays.binarySearch(nums, 6); // 返回-6
查找失败时,返回值=-(插入点+1)。例如查找6的返回值为-6,表示如果插入6应该放在索引5的位置(因为-(-6+1)=5)。
对象数组查找
String[] words = {"apple", "banana", "cherry"}; // 必须是有序数组
int pos = Arrays.binarySearch(words, "banana"); // 返回1
// 使用自定义比较器
String[] words = {"cherry", "banana", "apple"}; // 降序排列
int pos = Arrays.binarySearch(words, "banana", (a, b) -> b.compareTo(a));
指定范围查找
int[] arr = {1, 3, 5, 7, 9};
// 在索引1-3范围内(左闭右开区间)查找5
int idx = Arrays.binarySearch(arr, 1, 4, 5); // 返回2
3. 数组填充:fill()
fill()方法常用于数组初始化或重置数组值,特别适用于需要将数组所有元素设为相同值的情况。
基本用法
int[] arr = new int[5];
Arrays.fill(arr, 10); // [10, 10, 10, 10, 10]
boolean[] flags = new boolean[3];
Arrays.fill(flags, true); // [true, true, true]
指定范围填充
double[] values = new double[10];
// 将索引2到5的元素(左闭右开区间)设为3.14
Arrays.fill(values, 2, 6, 3.14);
String[] names = new String[5];
// 将前3个元素设为"Unknown"
Arrays.fill(names, 0, 3, "Unknown");
4. 数组比较:equals()与deepEquals()
equals()方法
用于比较一维数组的内容是否相同:
int[] a = {1, 2};
int[] b = {1, 2};
int[] c = {1, 2, 3};
System.out.println(Arrays.equals(a, b)); // true
System.out.println(Arrays.equals(a, c)); // false
String[] s1 = {"hello", "world"};
String[] s2 = {"hello", "world"};
System.out.println(Arrays.equals(s1, s2)); // true
deepEquals()方法
用于比较多维数组或嵌套数组的内容是否相同:
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
int[][] matrix3 = {{1, 2}, {3, 5}};
System.out.println(Arrays.deepEquals(matrix1, matrix2)); // true
System.out.println(Arrays.deepEquals(matrix1, matrix3)); // false
Object[] array1 = {1, new String[]{"a", "b"}};
Object[] array2 = {1, new String[]{"a", "b"}};
System.out.println(Arrays.deepEquals(array1, array2)); // true
5. 数组转字符串:toString()与deepToString()
toString()方法
将一维数组转换为可读的字符串表示:
int[] arr = {1, 2, 3};
System.out.println(Arrays.toString(arr)); // 输出:[1, 2, 3]
char[] chars = {'J', 'a', 'v', 'a'};
System.out.println(Arrays.toString(chars)); // 输出:[J, a, v, a]
deepToString()方法
将多维数组转换为可读的字符串表示:
int[][] matrix = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepToString(matrix)); // 输出:[[1, 2], [3, 4]]
String[][][] cube = {
{{"a", "b"}, {"c", "d"}},
{{"e", "f"}, {"g", "h"}}
};
System.out.println(Arrays.deepToString(cube));
// 输出:[[[a, b], [c, d]], [[e, f], [g, h]]]
6. 数组复制:copyOf()与copyOfRange()
copyOf()方法
复制数组,可以指定新的长度:
String[] original = {"a", "b", "c"};
// 复制为长度为5的新数组
String[] copy = Arrays.copyOf(original, 5); // ["a", "b", "c", null, null]
// 缩短数组
int[] numbers = {1, 2, 3, 4, 5};
int[] shortened = Arrays.copyOf(numbers, 3); // [1, 2, 3]
copyOfRange()方法
复制数组的指定范围:
int[] nums = {1, 2, 3, 4, 5};
// 复制索引1到3的元素(左闭右开区间)
int[] part = Arrays.copyOfRange(nums, 1, 4); // [2, 3, 4]
char[] chars = {'p', 'r', 'o', 'g', 'r', 'a', 'm'};
// 复制索引2到5的元素
char[] segment = Arrays.copyOfRange(chars, 2, 6); // ['o', 'g', 'r', 'a']
注意:copyOfRange()的结束索引是开区间,即不包含结束索引对应的元素。如果结束索引超出原数组长度,多余的位置会用默认值填充(数值类型为0,对象类型为null)。
三、注意事项
1.线程安全性扩展:
Arrays 类作为 Java 集合框架中的工具类,其设计遵循了无状态原则。所有方法(如 sort()、binarySearch()、fill() 等)都被声明为 static 且不依赖于任何实例变量,这从根本上保证了方法调用的线程安全性。具体表现为:
- 方法内部只使用局部变量和参数
- 不访问任何类级别的共享数据
- 不维护方法调用之间的状态
典型线程安全问题场景示例: 假设有两个线程同时操作同一个共享数组:
// 线程1
Arrays.sort(sharedArray);
// 线程2
sharedArray[0] = newValue;
这种情况下可能产生:
- 排序结果不一致
- ArrayIndexOutOfBoundsException
- 数据可见性问题
解决方案对比:
1.同步控制方案:
synchronized(lockObject) {
Arrays.sort(sharedArray);
}
2.线程安全包装方案:
List<Object> syncList = Collections.synchronizedList(Arrays.asList(sharedArray));
// 后续通过syncList进行操作
实际应用案例: 在电商平台的订单批量处理系统中,当多个工作线程同时处理订单数组时,必须对共享的订单数组使用 ReadWriteLock 进行细粒度并发控制。
2.对象数组操作扩展:
排序要求的完整实现方案:
方案一:实现 Comparable 接口(自然排序)
class Employee implements Comparable<Employee> {
private int id;
private String name;
private int salary;
@Override
public int compareTo(Employee other) {
// 按薪资升序
int salaryCompare = Integer.compare(this.salary, other.salary);
// 薪资相同则按ID排序
return salaryCompare != 0 ? salaryCompare : Integer.compare(this.id, other.id);
}
}
方案二:使用 Comparator(定制排序)
// 多维度比较器
Comparator<Employee> comparator = Comparator
.comparingInt(Employee::getSalary)
.thenComparing(Employee::getName)
.thenComparingInt(Employee::getId);
// 处理null值的比较器
Comparator<Employee> nullSafeComparator = Comparator.nullsFirst(
Comparator.comparing(Employee::getName, String.CASE_INSENSITIVE_ORDER)
);
// 使用示例
Arrays.sort(employees, comparator);
异常处理最佳实践:
1.对于可能包含null的数组:
Arrays.sort(array, Comparator.nullsFirst(Comparator.naturalOrder()));
2.类型安全检测:
if (array.length > 0 && !(array[0] instanceof Comparable)) {
throw new IllegalArgumentException("数组元素必须实现Comparable接口");
}
3.性能考量扩展:
算法实现细节:
-
双轴快速排序优化点:
- 选取5个候选元素的中位数作为基准
- 对小数组(<47)切换为插入排序
- 递归深度超过32时转为堆排序
-
TimSort 特性:
- 利用数据已有的有序性(runs)
- 最小合并区间为32
- 稳定排序(相等元素不交换)
内存使用分析:
// 基本类型数组:原址排序
int[] nums = new int[1_000_000]; // 约4MB内存
Arrays.sort(nums); // 不产生额外内存开销
// 对象数组:需要临时存储空间
Employee[] employees = new Employee[1_000_000]; // 约4MB引用空间
Arrays.sort(employees); // 额外需要约2MB临时空间
4.性能优化建议:
1.大数据量场景:
// 使用并行排序(需评估CPU核心数)
Arrays.parallelSort(largeArray);
// 分批处理
int batchSize = 100_000;
for (int i = 0; i < largeArray.length; i += batchSize) {
int end = Math.min(i + batchSize, largeArray.length);
Arrays.sort(largeArray, i, end);
}
2.高频排序场景:
// 重用数组而非新建
int[] reusableBuffer = new int[MAX_SIZE];
System.arraycopy(source, 0, reusableBuffer, 0, source.length);
Arrays.sort(reusableBuffer, 0, source.length);
监控指标建议:
- 单次排序耗时百分位(P99 < 50ms)
- GC 停顿时间占比(<1%)
- CPU 利用率(70-80%为佳)
&spm=1001.2101.3001.5002&articleId=150338515&d=1&t=3&u=bab91057d179405bb8f1ce43d87344c8)
852

被折叠的 条评论
为什么被折叠?



