本文纲要
- 二维数组概述
- 二维数组的动态初始化
- 二维数组访问元素的细节
- 二维数组的静态初始化
- 二维数组的遍历
- 二维数组求和
二维数组概述
二维数组本质上是一个容器,与一维数组不同的是,它内部存储的是一维数组(更准确地说,存储的是一维数组的引用)。可以把二维数组理解成一个“大容器”,里面装着多个“小容器”。
例如,有三个箱子分别装着啤酒,每个箱子就是一个一维数组;现在用一辆货车把这三个箱子一起运走,货车就相当于一个二维数组,它装载了三个一维数组。
应用场景:当一组数据需要按多个分组进行管理时,就很适合使用二维数组。例如,某公司按季度统计销售额,每个季度包含多个月份的数据,就可以用一个二维数组存储,其中每个一维数组代表一个季度的数据。
二维数组的动态初始化
1 ) 定义格式
数据类型[][] 数组名 = new 数据类型[m][n];
m:表示这个二维数组中可以存放多少个一维数组;
n:表示每个一维数组中可以存放多少个元素。
其他不太常用的写法:
数据类型 数组名[][] = new 数据类型[m][n];
数据类型[] 数组名[] = new 数据类型[m][n];
这三种写法都能创建二维数组,但第一种最常见。
示例
int[][] arr = new int[3][3];
上述代码创建了一个 int 类型的二维数组,可以存放 3 个一维数组,每个一维数组又可以存放 3 个 int 元素。
打印二维数组名
System.out.println(arr); // 例如输出:[[I@10f87f48
[[:中括号的数量代表数组的维度,两个中括号表示二维数组(一维数组为一个中括号);I:表示数组中存储的元素类型为 int;@:分隔符,无实际意义;10f87f48:十六进制内存地址。
动态初始化时的默认值
使用 new int[3][3] 动态初始化后,系统会自动为每个元素赋予默认值,int 类型的默认值为 0。以下代码可以验证:
System.out.println(arr[0][0]); // 0
System.out.println(arr[1][1]); // 0
System.out.println(arr[2][2]); // 0
访问与存储元素
访问二维数组中的元素需要使用两个索引:
arr[0][0] = 11; // 存储到第1个一维数组的第1个位置
arr[1][2] = 33; // 存储到第2个一维数组的第3个位置
System.out.println(arr[0][0]); // 取出第1个一维数组的第1个元素
注意事项:如果只使用一个索引,例如 arr[0],获取到的是该位置的一维数组的内存地址,而不是具体的元素值。
System.out.println(arr[0]); // 一维数组的地址,如 [I@... (一个中括号)
因此,二维数组实际上存储的是每个一维数组的引用(内存地址)
二维数组访问元素的细节
能否存入提前创建好的一维数组?
可以。例如:
int[] arr1 = {11, 22, 33};
int[] arr2 = {44, 55, 66};
int[] arr3 = {77, 88, 99, 100}; // 注意该数组长度为4,超过了原定长度3
int[][] arr = new int[3][3];
arr[0] = arr1;
arr[1] = arr2;
arr[2] = arr3; // 将 arr3 的引用赋给二维数组的第3个位置
System.out.println(arr[1][2]); // 66
System.out.println(arr[2][3]); // 100,可以正常访问
此时,arr[2] 原本指向一个长度为3的新数组,但被替换成了 arr3 的引用,因此现在 arr[2] 指向的是长度为4的数组。所以 arr[2][3] 可以正常访问,不会出现索引越界。
为什么这样不会报错,而直接赋值会报错?
如果直接使用传统方式:
arr[2][3] = 100; // 数组索引越界异常 ArrayIndexOutOfBoundsException
动态初始化 new int[3][3] 时,JVM 会立即创建好三个长度为3的一维数组,并将它们的引用存入二维数组。此时 arr[2] 指向的数组长度固定为3,索引只能到2,因此访问索引3会越界。
而如果我们先定义好一个长度为4的数组,再通过 arr[2] = arr3 替换引用,arr[2] 就不再指向原来的长度为3的数组,而是指向新的长度为4的数组,因此可以访问索引3。
原理图(使用 Mermaid 演示内存引用替换):
最初,arr[2] 指向一个长度为3的对象;执行 arr[2] = arr3 后,arr[2] 改为指向 arr3 所指向的长度为4的对象,因此可以访问 arr[2][3]。
二维数组的静态初始化
完整格式
数据类型[][] 数组名 = new 数据类型[][]{{元素1, 元素2...}, {元素1, 元素2...}...};
简化格式(常用)
数据类型[][] 数组名 = {{元素1, 元素2...}, {元素1, 元素2...}...};
示例
int[][] arr = {{11, 22, 33}, {44, 55, 66}};
System.out.println(arr[0][2]); // 33
也可以先创建好一维数组,再组合:
int[] arr1 = {11, 22, 33};
int[] arr2 = {44, 55, 66};
int[][] array = {arr1, arr2};
System.out.println(array[0][2]); // 33
二维数组的遍历
需求:已知二维数组 arr = {{11, 22, 33}, {33, 44, 55}},遍历并取出所有元素。
步骤:
- 遍历二维数组,取出每一个一维数组;
- 对每个一维数组继续进行遍历,获取内部存储的每一个元素。
代码实现:
int[][] arr = {{11, 22, 33}, {33, 44, 55}};
// 外层循环:遍历二维数组,得到每一个一维数组 arr[i]
for (int i = 0; i < arr.length; i++) {
// 内层循环:遍历当前一维数组,得到每一个元素
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
理解要点:arr[i] 是一个一维数组,arr[i].length 是该一维数组的长度,arr[i][j] 就是具体的元素值。
二维数组求和
1 )需求
某公司季度和月份统计数据如下(单位:万元),求全年总销售额。
第一季度:22, 66, 44
第二季度:77, 33, 88
第三季度:25, 45, 65
第四季度:11, 66, 99
2 ) 思路
- 定义求和变量 sum,初始化为 0;
- 使用二维数组存储数据,每个季度为一个一维数组,再将四个一维数组装入二维数组;
- 嵌套循环遍历二维数组,累加每个元素到 sum;
- 输出结果。
3 ) 代码实现
int sum = 0;
int[][] arr = {
{22, 66, 44},
{77, 33, 88},
{25, 45, 65},
{11, 66, 99}
};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
sum += arr[i][j];
}
}
System.out.println("全年总销售额:" + sum + "万元"); // 641
总结
二维数组是存储一维数组的容器,适合处理分组数据
动态初始化:new int[m][n],系统自动分配空间并赋予默认值,访问时使用两个索引
替换引用:arr[i] = existingArray 可以改变二维数组某位置指向的一维数组对象,从而突破原先的长度限制
静态初始化:使用 {{...}, {...}} 简化格式,直接在声明时赋值
遍历:嵌套循环,外层遍历二维数组,内层遍历每一个一维数组
求和:在遍历过程中累加即可
掌握这些内容,就可以游刃有余地使用二维数组解决实际问题了
676

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



