从零掌握Java数组操作:10个典型案例与实战解惑
目录导读
- 数组基础回顾:声明、初始化与内存图解
- 数组元素遍历与查找
- 数组排序(冒泡与快速排序实战)
- 数组插入与删除(动态扩容技巧)
- 数组拷贝与合并(深拷贝与浅拷贝区别)
- 数组去重与统计(高频面试题)
- 二维数组操作(矩阵转置与求和)
- 数组与集合互转(List与Array的桥梁)
- 数组流式处理(Java 8 Stream API)
- 数组工具类Arrays详解
- 数组异常处理(NullPointer与IndexOutOfBounds)
- 问答环节:5个常见误区与解决方案
数组基础回顾
Java中的数组是存储固定大小同类型元素的容器,理解其本质对后续操作至关重要。

声明与初始化:
// 声明
int[] arr1;
// 静态初始化(直接赋值)
int[] arr2 = {1, 2, 3, 4};
// 动态初始化(指定长度)
String[] names = new String[5]; // 默认值null
内存图解:
数组在堆内存中是一块连续的空间,栈中的引用变量指向该空间的首地址。
典型错误:arr1 = {5, 6, 7}; 这种写法非法,必须用new或直接初始化。
案例一:数组元素遍历与查找
需求: 给定整数数组,查找目标值是否存在并返回下标。
代码实现:
public static int linearSearch(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1; // 未找到
}
优化技巧:
- 若数组有序,可用二分查找(时间复杂度O(log n))。
- 使用增强for循环遍历但不适合返回下标。
案例二:数组排序
冒泡排序(稳定):
for (int i = 0; i < arr.length - 1; i++) {
boolean swapped = false;
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
swapped = true;
}
}
if (!swapped) break; // 优化:没有交换则提前退出
}
快速排序(递归):
使用Arrays.sort(arr)即可,底层采用双轴快排,平均O(n log n)。
案例三:数组插入与删除
数组长度固定,插入/删除需要创建新数组。
插入操作:
public static int[] insertElement(int[] arr, int index, int value) {
int[] newArr = new int[arr.length + 1];
System.arraycopy(arr, 0, newArr, 0, index);
newArr[index] = value;
System.arraycopy(arr, index, newArr, index + 1, arr.length - index);
return newArr;
}
删除操作:
类似思路,跳过目标索引复制即可。
注意:频繁的插入删除建议用ArrayList。
案例四:数组拷贝与合并
浅拷贝 vs 深拷贝:
System.arraycopy()、Arrays.copyOf()属于浅拷贝(对象数组拷贝引用)。- 深拷贝需手动复制每个对象或使用序列化。
合并两个数组:
int[] merged = new int[arr1.length + arr2.length]; System.arraycopy(arr1, 0, merged, 0, arr1.length); System.arraycopy(arr2, 0, merged, arr1.length, arr2.length);
案例五:数组去重与统计
痛点: 原始数组无序时如何高效去重?
方案:利用HashSet(推荐):
List<Integer> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
for (int num : arr) {
if (set.add(num)) {
list.add(num); // 保留首次出现的顺序
}
}
统计元素频率:
使用HashMap<Integer, Integer>。
案例六:二维数组操作
矩阵转置:
int[][] matrix = {{1,2}, {3,4}, {5,6}}; // 3行2列
int rows = matrix.length;
int cols = matrix[0].length;
int[][] transposed = new int[cols][rows];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
transposed[j][i] = matrix[i][j];
}
}
计算对角线之和: 注意方阵行列相等。
案例七:数组与集合互转
int[] 转 List
// 错误方式:Arrays.asList(int[]) 返回List<int[]> 并非List<Integer>
int[] arr = {1,2,3};
List<Integer> list = Arrays.stream(arr).boxed().collect(Collectors.toList());
List变数组:
String[] array = list.toArray(new String[0]); // 推荐指定长度为0
案例八:数组流式处理
Java 8 Stream API 示例:
int[] numbers = {5, 3, 8, 1, 9};
int sum = Arrays.stream(numbers).sum();
double avg = Arrays.stream(numbers).average().orElse(0);
int[] filtered = Arrays.stream(numbers).filter(n -> n > 4).toArray();
并行处理:
Arrays.stream(numbers).parallel().forEach(...) 适合大数据量。
案例九:数组工具类Arrays详解
| 方法 | 用途 | 示例 |
|---|---|---|
sort() |
排序 | Arrays.sort(arr, 1, 4) 对部分排序 |
binarySearch() |
二分查找前需排序 | int idx = Arrays.binarySearch(arr, 3); |
fill() |
填充 | Arrays.fill(arr, 0); |
equals() |
比较数组内容 | Arrays.equals(a, b) |
toString() |
打印 | Arrays.toString(arr) |
注意: equals()和deepEquals()区别(后者用于多维数组)。
案例十:数组异常处理
常见运行时异常:
ArrayIndexOutOfBoundsException:访问越界。NullPointerException:对null数组调用length。
防御性代码:
if (arr != null && arr.length > 0) {
// 安全操作
}
问答环节:5个常见误区与解决方案
Q1: int[] a = new int[3]{1,2,3}; 为什么编译报错?
A: 动态初始化和静态初始化不能混用,正确写法:int[] a = {1,2,3};或new int[]{1,2,3};。
Q2: 数组的length是方法还是属性?
A: 是属性(arr.length),不是方法,String的length()是方法。
Q3: 如何高效地让数组所有元素乘以2?
A: 原始写法循环赋值;若使用Stream:Arrays.stream(arr).map(n -> n*2).toArray()。
Q4: 为什么Arrays.asList()返回的List不能调用add()?
A: 返回的java.util.Arrays.ArrayList是内部类,固定大小,不支持增删操作。
Q5: 两个数组内容相同,但arr1.equals(arr2)返回false?
A: 数组没有重写equals(),默认比较引用,应使用Arrays.equals(arr1, arr2)。