Java中多维数组本质是“数组的数组”,声明推荐int[][] arr,禁用int3 arr;初始化需分步new,支持不规则数组,静态初始化仅限声明时。

Java中多维数组的声明方式区别于C/C++
Java没有真正意义上的“多维数组”,只有“数组的数组”。这意味着 int[][] 实际上是一个 int[] 类型的引用数组,每个元素又指向一个一维 int[]。声明时方括号位置影响语义:int[][] arr 合法,int[] arr[] 虽然语法允许(为兼容C风格),但不推荐;int[] arr[] 容易让人误以为是“数组+指针”混合结构,实际仍是引用数组。
常见错误:写成 int[3][4] arr —— 这在Java中非法,维度大小不能出现在声明阶段。
-
int[][] matrix:推荐,清晰表达“二维引用数组” -
int[] matrix[]:可编译,但语义模糊,IDE通常会警告 -
int matrix[][]:编译失败,方括号不能紧贴变量名
初始化必须分两步:分配外层数组 + 分配内层数组
Java不支持像C那样用 {{1,2},{3,4}} 一步完成堆内存分配(除非在声明同时使用静态初始化器)。运行时创建需显式调用 new 两次:
int[][] grid = new int[2][]; grid[0] = new int[3]; // 第一行长度为3 grid[1] = new int[5]; // 第二行长度为5(可不等长)
这种“不规则数组”(jagged array)是合法且常见的。若要规则矩形结构,可简写为:new int[2][3],此时JVM自动为每行分配长度为3的一维数组。
立即学习“Java免费学习笔记(深入)”;
- 静态初始化器只能用于声明时:
int[][] a = {{1,2}, {3,4,5}}; -
new int[2][3]等价于先new int[2][]再循环new int[3] - 忘记给某行赋值(如只做
new int[2][]就访问grid[0][0])会触发NullPointerException
遍历与索引访问要注意空指针和越界风险
由于每行长度可能不同,用 for (int i = 0; i 遍历外层后,内层必须检查 arr[i] != null 并用 arr[i].length 获取当前行长度,不能直接套用固定列数。
for (int i = 0; i < matrix.length; i++) {
if (matrix[i] != null) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
}
System.out.println();
}- 访问
matrix[i][j]前,必须确保i 且j -
matrix[i]可能为null,尤其在手动分配不完整时 - 增强for循环(
for (int[] row : matrix))可避免外层索引错误,但无法获知当前行号
性能与内存布局:每行独立分配,缓存不友好
Java多维数组在内存中不是连续块。new int[1000][1000] 会先分配1000个引用,再分配1000个长度为1000的 int[] 对象,共1001个对象。这带来两重开销:GC压力增大、CPU缓存命中率低(行间跳转导致cache line失效)。
- 对性能敏感场景(如数值计算),优先考虑一维数组模拟二维:
int[] flat = new int[rows * cols],用flat[i * cols + j]访问 -
ArrayList不能替代int[][]—— 泛型擦除后存储的是Object[],装箱/拆箱开销大 - 使用
Arrays.deepToString()打印调试,比手写嵌套循环快且安全
最易被忽略的是:即使声明为 int[][],只要某行未初始化,它就是 null;而C语言里类似声明必有确定内存布局,这点差异常导致NPE排查困难。










