Java数组总结
·
Java 数组总结
作者:没有四次元口袋的蓝胖
日期:2026-06-02
标签:Java, 基础语法, 数组
一、什么是数组?
数组是相同类型数据的有序集合,在内存中连续存储。核心特点:
| 特性 | 说明 |
|---|---|
| 固定长度 | 创建后长度不可变 |
| 同类型 | 所有元素类型一致 |
| 连续内存 | 通过索引高效随机访问 |
| 索引从 0 开始 | 最后一个元素索引为 length - 1 |
二、一维数组
2.1 声明与初始化
声明(两种写法等价)
int[] arr; // 推荐,类型和变量分离清晰
int arr[]; // C 风格,不推荐
静态初始化(声明时直接赋值)
int[] arr = {1, 2, 3, 4, 5};
// 完整写法
int[] arr = new int[]{1, 2, 3, 4, 5};
动态初始化(指定长度,默认值填充)
int[] arr = new int[5]; // 5个元素,默认值为 0
各类型默认值:
| 数据类型 | 默认值 |
|---|---|
byte / short / int / long |
0 |
float / double |
0.0 |
char |
'\u0000' |
boolean |
false |
| 引用类型(String 等) | null |
2.2 访问与遍历
通过索引访问
int[] arr = {10, 20, 30};
System.out.println(arr[0]); // 10
System.out.println(arr[2]); // 30
arr[1] = 99; // 修改
System.out.println(arr[1]); // 99
⚠️ 索引越界会抛出
ArrayIndexOutOfBoundsException,这是运行时异常,编译器不会提前报错。
三种遍历方式
int[] arr = {10, 20, 30, 40, 50};
// 1. 普通 for(可获取索引,可修改元素)
for (int i = 0; i < arr.length; i++) {
System.out.println("arr[" + i + "] = " + arr[i]);
}
// 2. 增强 for / for-each(简洁,但拿不到索引)
for (int num : arr) {
System.out.println(num);
}
// 3. Arrays.toString()(快速打印,调试常用)
System.out.println(Arrays.toString(arr));
// 输出:[10, 20, 30, 40, 50]
2.3 常见操作
求最大值 / 最小值
int[] arr = {34, 12, 89, 5, 67};
int max = arr[0], min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) max = arr[i];
if (arr[i] < min) min = arr[i];
}
System.out.println("最大值:" + max); // 89
System.out.println("最小值:" + min); // 5
求和与平均值
int[] arr = {10, 20, 30, 40};
int sum = 0;
for (int num : arr) {
sum += num;
}
double avg = (double) sum / arr.length;
System.out.println("总和:" + sum); // 100
System.out.println("平均值:" + avg); // 25.0
查找元素
int[] arr = {5, 3, 8, 1, 9};
int target = 8;
int index = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
index = i;
break;
}
}
System.out.println("索引:" + index); // 2
反转数组
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
System.out.println(Arrays.toString(arr));
// 输出:[5, 4, 3, 2, 1]
三、二维数组
3.1 概念
二维数组本质是**“数组的数组”**——每个元素本身又是一个一维数组。
int[][] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
内存视角:
arr ──→ [ 引用1 , 引用2 , 引用3 ]
│ │ │
▼ ▼ ▼
[1,2,3] [4,5,6] [7,8,9]
3.2 声明与初始化
静态初始化
int[][] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
动态初始化——规则矩阵
// 3行4列,所有元素默认为 0
int[][] arr = new int[3][4];
动态初始化——不规则矩阵(锯齿数组)
// 只指定行数,列数后续单独分配
int[][] arr = new int[3][];
arr[0] = new int[2]; // 第0行:2列
arr[1] = new int[4]; // 第1行:4列
arr[2] = new int[1]; // 第2行:1列
这是 Java 二维数组的灵活性所在:每行的列数可以不同,因为它本质上是一维引用数组。
3.3 访问与遍历
访问元素
int[][] arr = {
{1, 2, 3},
{4, 5, 6}
};
System.out.println(arr[0][1]); // 2(第0行第1列)
System.out.println(arr[1][2]); // 6(第1行第2列)
System.out.println(arr.length); // 2(行数)
System.out.println(arr[0].length); // 3(第0行的列数)
遍历方式
int[][] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 1. 嵌套 for 循环
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
// 2. 嵌套 for-each
for (int[] row : arr) {
for (int num : row) {
System.out.print(num + " ");
}
System.out.println();
}
// 3. Arrays.deepToString()(调试神器)
System.out.println(Arrays.deepToString(arr));
// 输出:[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3.4 常见操作
矩阵转置
int[][] matrix = {
{1, 2, 3},
{4, 5, 6}
};
// 2×3 → 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];
}
}
// transposed = {{1,4}, {2,5}, {3,6}}
对角线求和
int[][] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int mainSum = 0; // 主对角线
int antiSum = 0; // 副对角线
for (int i = 0; i < arr.length; i++) {
mainSum += arr[i][i];
antiSum += arr[i][arr.length - 1 - i];
}
System.out.println("主对角线和:" + mainSum); // 15 (1+5+9)
System.out.println("副对角线和:" + antiSum); // 15 (3+5+7)
杨辉三角
int n = 6;
int[][] triangle = new int[n][];
for (int i = 0; i < n; i++) {
triangle[i] = new int[i + 1];
triangle[i][0] = 1; // 每行首元素
triangle[i][i] = 1; // 每行末元素
for (int j = 1; j < i; j++) {
triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j];
}
}
for (int[] row : triangle) {
System.out.println(Arrays.toString(row));
}
// [1]
// [1, 1]
// [1, 2, 1]
// [1, 3, 3, 1]
// [1, 4, 6, 4, 1]
// [1, 5, 10, 10, 5, 1]
四、Arrays 工具类常用方法
java.util.Arrays 是操作数组的工具类,面试和开发都高频使用。
| 方法 | 作用 | 示例 |
|---|---|---|
toString() |
一维数组转字符串 | Arrays.toString(arr) |
deepToString() |
多维数组转字符串 | Arrays.deepToString(arr2D) |
sort() |
升序排序(双轴快排) | Arrays.sort(arr) |
binarySearch() |
二分查找(需先排序) | Arrays.binarySearch(arr, 5) |
fill() |
填充相同值 | Arrays.fill(arr, 0) |
equals() |
比较一维数组内容 | Arrays.equals(a, b) |
deepEquals() |
比较多维数组内容 | Arrays.deepEquals(a, b) |
copyOf() |
复制指定长度 | Arrays.copyOf(arr, 10) |
copyOfRange() |
复制指定范围 | Arrays.copyOfRange(arr, 1, 4) |
使用示例
int[] arr = {5, 2, 8, 1, 9, 3};
// 排序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
// [1, 2, 3, 5, 8, 9]
// 二分查找(必须先排序)
int idx = Arrays.binarySearch(arr, 5);
System.out.println("5 的索引:" + idx); // 3
// 复制并扩容
int[] newArr = Arrays.copyOf(arr, 10);
System.out.println(Arrays.toString(newArr));
// [1, 2, 3, 5, 8, 9, 0, 0, 0, 0]
// 填充
Arrays.fill(newArr, 6, 10, 100);
System.out.println(Arrays.toString(newArr));
// [1, 2, 3, 5, 8, 9, 100, 100, 100, 100]
五、数组常见坑与面试考点
坑 1:数组引用赋值 vs 拷贝
int[] a = {1, 2, 3};
int[] b = a; // 引用赋值!a 和 b 指向同一个数组
b[0] = 99;
System.out.println(a[0]); // 99 ← a 也被修改了
// 正确的拷贝方式
int[] c = Arrays.copyOf(a, a.length); // 深拷贝
c[0] = 0;
System.out.println(a[0]); // 99 ← a 不受影响
坑 2:数组长度不可变
int[] arr = {1, 2, 3};
// arr.length = 5; // 编译错误!length 是 final 的
// 想"扩容"只能创建新数组
arr = Arrays.copyOf(arr, 5); // [1, 2, 3, 0, 0]
坑 3:二维数组每行长度可以不同
int[][] arr = new int[3][];
arr[0] = new int[2];
arr[1] = new int[4];
arr[2] = new int[1];
// 遍历时不能用 arr[0].length 代表所有行的列数!
// 必须用 arr[i].length 逐行获取
坑 4:Arrays.sort() 是升序,如何降序?
// 方法1:装箱后用 Comparator(只能对引用类型)
Integer[] arr = {5, 2, 8, 1, 9};
Arrays.sort(arr, Collections.reverseOrder());
// 方法2:升序排完后手动反转
int[] arr2 = {5, 2, 8, 1, 9};
Arrays.sort(arr2);
// 反转...
面试高频题:数组 vs ArrayList
| 对比维度 | 数组 | ArrayList |
|---|---|---|
| 长度 | 固定 | 动态扩容 |
| 存储类型 | 基本类型 + 引用类型 | 只能引用类型(int → Integer) |
| 速度 | 更快(无装箱开销) | 略慢 |
| 功能 | 基础 | 丰富(add/remove/contains 等) |
| 使用场景 | 长度已知、性能敏感 | 长度可变、操作频繁 |
六、思维导图速览
数组
├── 一维数组
│ ├── 声明与初始化(静态 / 动态)
│ ├── 访问与遍历(for / for-each / toString)
│ ├── 常见操作(最值 / 求和 / 查找 / 反转)
│ └── 默认值(0 / null / false)
├── 二维数组
│ ├── 本质:数组的数组
│ ├── 初始化(规则 / 锯齿)
│ ├── 遍历(嵌套循环 / deepToString)
│ └── 常见操作(转置 / 对角线 / 杨辉三角)
├── Arrays 工具类
│ ├── sort / binarySearch / fill
│ ├── copyOf / copyOfRange
│ ├── toString / deepToString
│ └── equals / deepEquals
└── 常见坑
├── 引用赋值 ≠ 拷贝
├── 长度不可变
├── 锯齿数组行宽不同
└── 降序排序技巧
写在最后
数组是 Java 最基础的数据结构,也是后续学习集合框架、排序算法、动态规划的重要基石。建议:
- 动手敲:杨辉三角、矩阵转置这些题目,自己从零写一遍比看十遍有用。
- 理解引用模型:Java 数组是引用类型,搞清楚"赋值是共享还是拷贝"能避免很多 bug。
- 关注边界:空数组(
arr.length == 0)和 null 数组是两个概念,别混淆。
更多推荐
所有评论(0)