Java二维数组本质是“数组的数组”,外层数组连续存储引用,内层数组独立分配、彼此不连续;支持规则与不规则结构,访问时先解引用再校验对应行长度。

Java中没有真正意义上的“不规则矩阵数组”,它本质是一维数组的数组,底层存储结构完全基于引用机制,而非连续内存块。
核心:二维数组就是对象数组
声明 int[][] arr = new int[3][] 时,JVM只在堆上分配一个长度为3的一维数组,这个数组的每个元素类型是 int[](即“指向一维数组的引用”),初始值全为 null。它不占用任何 int 类型数据空间,只是存了3个“空地址”。
- 这个外层数组本身是连续的——3个引用变量在堆中挨着存放
- 但每行实际的
int[]是独立对象,各自在堆中申请内存,彼此位置无关 - 各行长度不同,是因为它们是不同大小的独立一维数组,互不影响
内存布局示意图(逻辑而非物理连续)
假设执行:
int[][] jagged = new int[3][]; jagged[0] = new int[2]; // 地址A jagged[1] = new int[5]; // 地址B jagged[2] = new int[3]; // 地址C
那么堆内存中实际存在:
立即学习“Java免费学习笔记(深入)”;
- 一个含3个引用的数组:[A, B, C](连续存放)
- 三个独立的
int[]对象:分别占2、5、3个int单元,散落在堆各处 - 栈中只有变量名
jagged,它存的是外层数组的首地址(即 [A,B,C] 的起始位置)
为什么不会出现“错位访问”或“越界自动对齐”?
因为每次访问 jagged[i][j] 都分两步:
- 先查外层数组第
i项(得到引用值,比如地址B) - 再用该地址去读对应一维数组的第
j个元素——此时校验的是该一维数组自己的.length
所以 jagged[1].length == 5,而 jagged[2].length == 3,二者毫无关系。不存在统一的“列边界”,也没有隐式填充或截断。
和规整二维数组的关键区别
对比 int[][] regular = new int[3][4]:
- 它会一次性分配 3×4=12 个连续
int空间,并按行主序排布 - 所有行共享同一套列维度约束,
regular[i].length恒为4 - 底层仍是“数组的数组”,但JVM在创建时就为每行预分配了相同长度的一维数组
而不规则形式把“每行分配动作”从初始化阶段延迟到运行时,靠手动赋值触发,从而释放了长度一致性约束。

















