Java多维数组不是连续内存而是“数组的数组”,外层数组存引用,内层数组独立分配在堆中且物理地址不相连;访问matrixi需两次寻址,缓存局部性差,与C/C++单一连续块有本质区别。

Java 多维数组不是一块连续内存,而是“数组的数组”——外层数组存引用,内层数组各自独立分配在堆中,物理地址互不相连。
二维数组的典型内存结构
声明 int[][] matrix = new int[3][4] 时,JVM 实际做了两件事:
- 在堆中创建一个长度为 3 的引用型一维数组(外层数组),每个元素初始为 null
- 紧接着为每一行分配一段连续的 int 内存:共 3 块,每块含 4 个 int,但三块内存可能分散在堆的不同区域
这种结构意味着 matrix[1][2] 的访问需两次寻址:先通过外层数组拿到第 1 行的引用,再用该引用定位到对应子数组,最后按一维方式计算偏移(即 base + 2 * 4)。
不规则二维数组(锯齿数组)的合法写法
Java 允许各行长度不同,本质正是源于“每行单独 new”:
立即学习“Java免费学习笔记(深入)”;
- int[][] jagged = new int[3][]; → 只建外层数组,长度 3,内容全 null
- jagged[0] = new int[2]; → 第 0 行:2 个 int,独立内存块
- jagged[1] = new int[5]; → 第 1 行:5 个 int,另起一块
- jagged[2] = new int[1]; → 第 2 行:1 个 int,再起一块
访问 jagged[1][3] 不会越界,但访问 jagged[0][3] 会抛 ArrayIndexOutOfBoundsException —— 因为第 0 行只有 2 个元素。
与 C/C++ 二维数组的本质区别
C 中 int arr[3][4] 是单一连续内存块(共 12 个 int),地址可通过公式 base + (i * 4 + j) * sizeof(int) 直接算出;Java 没有这种底层连续性:
- 外层数组是对象:含对象头、length 字段、数据区(存 3 个引用)
- 每个内层数组也是独立对象:各自有对象头、length、连续的数据区
- 所以 matrix[i][j] 必须经历两次解引用,无法做线性地址跳转
这导致 Java 多维数组缓存局部性较差,尤其在科学计算中反复遍历大矩阵时容易引发 Cache Miss。
三维及更高维数组的嵌套逻辑
三维数组 int[][][] cube 的结构层层递进:
- 最外层数组元素类型是 int[][],即二维数组引用
- 每个该引用指向一个二维数组对象,而该二维数组本身又是“一维数组引用”的集合
- 依此类推,每一层都是引用嵌套,不存在跨维度的连续布局
初始化 cube[0][1][2] 时,JVM 依次查外层 → 中层 → 内层,共三次对象寻址,开销随维度增加而上升。


















