Java数组操作终极指南:从入门到实战(含图表示例)

Java数组操作终极指南:从入门到实战
概述
数组是Java中最基础、最常用的数据结构之一。它是一种固定长度、相同类型元素的连续存储结构。无论是存储基本类型还是对象引用,数组都能高效地完成数据批量处理。本文将从零开始,系统梳理Java数组的声明、初始化、遍历、复制、排序、查找、转换等所有核心操作,并给出实战场景和避坑指南。文中图表使用 Mermaid 语法绘制,可在 VuePress 等支持 Mermaid 的 Markdown 渲染器中正常显示。
核心概念
1. 声明与创建
// 方式一:先声明,再分配空间
int[] arr1;
arr1 = new int[5];
// 方式二:声明并分配空间
int[] arr2 = new int[5];
// 方式三:静态初始化(直接指定元素)
int[] arr3 = {1, 2, 3, 4, 5};
// 方式四:匿名数组(常用于方法参数)
printArray(new int[]{10, 20, 30});
注意:
int[] arr = new int[5]会分配5个int类型的空间,每个元素默认值为0。
2. 访问与修改
通过下标索引(从0开始)访问或修改元素:
int[] scores = {85, 92, 78};
System.out.println(scores[1]); // 92
scores[0] = 90;
3. 数组长度
每个数组都有一个 length 属性(注意不是方法):
int[] arr = new int[10];
int len = arr.length; // 10
4. 遍历方式
4.1 普通for循环
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
4.2 增强for循环(forEach)
for (int value : arr) {
System.out.println(value);
}
5. 多维数组
Java中多维数组本质是“数组的数组”。
// 声明二维数组
int[][] matrix = new int[3][4];
// 静态初始化
int[][] grid = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 不规则数组(每行长度可以不同)
int[][] ragged = new int[3][];
ragged[0] = new int[2];
ragged[1] = new int[3];
ragged[2] = new int[1];
遍历二维数组:
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[i].length; j++) {
System.out.print(grid[i][j] + " ");
}
System.out.println();
}
实战操作
1. 数组复制
1.1 使用 `System.arraycopy()`
底层原生方法,效率最高:
int[] src = {1, 2, 3, 4, 5};
int[] dest = new int[5];
System.arraycopy(src, 0, dest, 0, src.length);
// dest = {1, 2, 3, 4, 5}
1.2 使用 `Arrays.copyOf()`
int[] copy = Arrays.copyOf(src, src.length);
// 还可指定新长度,多余补默认值
int[] shortCopy = Arrays.copyOf(src, 3); // {1,2,3}
1.3 使用 `clone()`
int[] cloneArr = src.clone();
注意:
clone()对一维基本类型数组是深拷贝,对对象数组是浅拷贝。
2. 数组排序
2.1 基本类型排序(升序)
int[] nums = {3, 1, 4, 1, 5, 9};
Arrays.sort(nums);
// nums = {1, 1, 3, 4, 5, 9}
2.2 对象排序(需实现 Comparable 或提供 Comparator)
String[] names = {"Tom", "Alice", "Bob"};
Arrays.sort(names); // 按字典序:"Alice", "Bob", "Tom"
// 自定义排序(降序)
Arrays.sort(names, (a, b) -> b.compareTo(a));
2.3 部分排序(指定范围)
int[] arr = {3, 2, 1, 4, 5};
Arrays.sort(arr, 0, 3); // 只对前3个排序:{1,2,3,4,5}
3. 二分查找
前提:数组必须已排序。
int[] nums = {1, 3, 5, 7, 9};
int index = Arrays.binarySearch(nums, 5); // 返回2
int notFound = Arrays.binarySearch(nums, 4); // 返回负数(-(插入点)-1)
4. 填充与比较
int[] arr = new int[5];
Arrays.fill(arr, 100); // arr = {100,100,100,100,100}
// 数组比较(元素逐个比较)
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(Arrays.equals(a, b)); // true
// 深层比较(用于多维数组)
int[][] deepA = {{1},{2}};
int[][] deepB = {{1},{2}};
System.out.println(Arrays.deepEquals(deepA, deepB)); // true
5. 转 List
String[] arr = {"a", "b", "c"};
List<String> list = Arrays.asList(arr);
// 注意:返回的 List 大小固定,不能 add/remove,但可以 set
若要可变 List:
List<String> mutableList = new ArrayList<>(Arrays.asList(arr));
6. 流操作(Java 8+)
利用 Arrays.stream() 可以方便地进行过滤、映射、归约等操作:
int[] nums = {1, 2, 3, 4, 5};
// 求和
int sum = Arrays.stream(nums).sum();
// 筛选偶数
int[] evens = Arrays.stream(nums).filter(n -> n % 2 == 0).toArray();
// 映射为字符串
String[] strs = Arrays.stream(nums)
.mapToObj(String::valueOf)
.toArray(String[]::new);
7. 并行操作(并行排序、并行前缀)
int[] data = {5, 3, 1, 4, 2};
Arrays.parallelSort(data); // 多线程排序(大数据量时性能优)
// 并行前缀(累加)
int[] prefix = {1, 2, 3, 4};
Arrays.parallelPrefix(prefix, (x, y) -> x + y);
// prefix = {1, 3, 6, 10}
8. 数组转为字符串
int[] arr = {1, 2, 3};
System.out.println(Arrays.toString(arr)); // [1, 2, 3]
// 多维数组
int[][] matrix = {{1,2},{3,4}};
System.out.println(Arrays.deepToString(matrix)); // [[1, 2], [3, 4]]
9. 比较与哈希
int[] a = {1, 2};
int[] b = {1, 2};
System.out.println(a.equals(b)); // false(比较的是引用)
System.out.println(Arrays.equals(a, b)); // true
// 计算哈希码(常用于集合)
int hash = Arrays.hashCode(a);
10. 实战:数组去重
public static int[] removeDuplicates(int[] nums) {
return Arrays.stream(nums)
.distinct()
.toArray();
}
11. 实战:数组合并
int[] first = {1, 2};
int[] second = {3, 4};
int[] combined = new int[first.length + second.length];
System.arraycopy(first, 0, combined, 0, first.length);
System.arraycopy(second, 0, combined, first.length, second.length);
// or use Stream
int[] merged = IntStream.concat(Arrays.stream(first), Arrays.stream(second)).toArray();
图表与流程解析
以下使用 Mermaid 绘制数组操作的核心流程图,展示从创建到最终输出结果的典型路径:
flowchart TD
A[声明数组] --> B{初始化方式?}
B -->|静态| C[直接赋值元素]
B -->|动态| D[new 类型[长度]]
C --> E[获取长度 .length]
D --> E
E --> F[遍历/修改元素]
F --> G{需要复制?}
G -->|是| H[System.arraycopy / Arrays.copyOf / clone]
G -->|否| I{需要排序?}
I -->|是| J[Arrays.sort / parallelSort]
I -->|否| K[执行其他操作: 查找/转换/流处理]
J --> K
H --> K
K --> L[输出结果 Arrays.toString]
此外,二维数组的内存布局可表示为:
graph LR
subgraph 二维数组引用
A[matrix] --> B[第0行引用]
A --> C[第1行引用]
A --> D[第2行引用]
end
subgraph 实际一维数组
B --> E[0,1,2]
C --> F[3,4,5]
D --> G[6,7,8]
end
注意事项(避坑指南)
- 数组越界:下标范围
0 ~ length-1,访问arr[length]会抛出ArrayIndexOutOfBoundsException。 - 默认值:基本类型数组元素有默认值(int:0, double:0.0, boolean:false),引用类型数组默认值为
null。 - 对象数组是引用:
Object[] objs = new Object[3]中存的是引用,修改引用对象的属性会影响所有指向该对象的元素。 - 静态初始化不能拆分:
int[] arr; arr = {1,2,3};非法,必须写成arr = new int[]{1,2,3}; - length 是属性不是方法:不要写成
arr.length()。 - Arrays.asList() 的坑:返回的 List 由原数组支持,大小固定,不能
add/remove;且如果数组是基本类型,asList()会将整个数组作为单个元素返回,应使用IntStream。 - 浅拷贝与深拷贝:
clone()和System.arraycopy()对基本类型数组是深拷贝,对对象数组是浅拷贝(只复制引用)。需要深拷贝对象数组时需手动遍历或使用序列化。 - 并行排序的性能:
parallelSort()适用于大规模数据(>几千),小数组使用sort()更快。 - 不要使用
==比较数组内容:==比较的是引用地址,应使用Arrays.equals()。
总结
Java 数组虽然简单,但背后涉及声明、初始化、赋值、遍历、复制、排序、查找、转换、流式操作等一系列实用技巧。理解这些核心操作可以让你在日常编码中高效处理批量数据。建议记住以下常用 API:
| 操作 | 关键方法 |
|---|---|
| 复制 | System.arraycopy(), Arrays.copyOf(), clone() |
| 排序 | Arrays.sort(), Arrays.parallelSort() |
| 查找 | Arrays.binarySearch() |
| 填充 | Arrays.fill() |
| 比较 | Arrays.equals(), Arrays.deepEquals() |
| 转字符串 | Arrays.toString(), Arrays.deepToString() |
| 转List | Arrays.asList() |
| 流处理 | Arrays.stream() |
掌握这些内容后,你就能自信地说:“数组操作,我全栈了!”
本文使用 Mermaid 图表辅助说明,在支持 Mermaid 的 Markdown 编辑器(如 VuePress、Typora、GitHub)中可正常渲染。
