java不规则二维数组本质是“一维数组的数组”,需外层定行数、内层各行按需分配;动态初始化先声明外层数组再逐行分配,静态初始化用花括号自动确定每行长度,遍历时必须先判空再取length。

Java 不规则二维数组(锯齿数组)不是“特殊技巧”,而是语言底层机制的自然体现:它本质是「一维数组的数组」,每行独立分配、互不影响。构建得当能显著节省内存,尤其在稀疏或梯形结构场景下;但若忽略空行判别和访问逻辑,极易引发运行时异常。
怎么声明和初始化才真正“不规则”
关键在**外层只定行数,内层各行按需分配**——不能用 new int[3][4] 这类固定列数方式,那会生成规则矩阵,失去灵活性。
-
动态初始化(推荐用于运行时结构不确定):
先声明外层数组:int[][] data = new int[5][];→ 此时data.length == 5,但所有data[i]均为null;
再逐行分配长度:data[0] = new int[2]; data[1] = new int[7]; data[3] = new int[0];(空数组合法) -
静态初始化(适合编译期已知结构):
String[][] names = { {"Alice", "Bob"}, {"Charlie"}, {}, {"David", "Eve", "Frank", "Grace"} };
每行长度由花括号内元素个数自动确定,第三行为空数组(.length == 0) -
混合方式(兼顾可读性与灵活性):
部分行直接初始化,部分行延迟分配:int[][] grid = { new int[]{1, 2}, null, new int[3] };→ 第二行显式设为null,后续可单独赋值
遍历时必须绕开的两个坑
不规则数组遍历不是语法问题,而是逻辑安全问题。多数崩溃源于对 null 或长度假设的误判。
-
永远先判空,再取 length:
错误写法:for (int j = 0; j → 若 <code>arr[i] == null,立刻抛NullPointerException;
正确写法:if (arr[i] != null) { for (int j = 0; j -
别依赖 arr[0].length 做统一列长判断:
规则数组常用arr[0].length代表列数,但在不规则数组中毫无意义;
每一行长度必须单独获取:arr[i].length是唯一有效值 -
增强 for 循环更易踩坑:
for (int[] row : arr) { for (int x : row) { ... } }→ 外层row可能为null,内层循环直接崩;
务必加if (row != null)保护
内存使用率优势在哪?看真实对比
以存储一个“上三角”结构(第 i 行含 i+1 个元素,共 10 行)为例:
-
规则二维数组:
new int[10][10]→ 分配 10×10 = 100 个int单元,实际只用 55 个,内存浪费 45%; -
不规则数组:
new int[10][]后逐行分配new int[1], new int[2], ..., new int[10]→ 总共分配 55 个int,零冗余; -
注意点:外层数组本身有固定开销(如 10 个引用空间),但相比整块填充的规则数组,整体堆内存占用仍大幅下降;
原始类型(int[][])无装箱开销,比ArrayList<arraylist>></arraylist>更紧凑、缓存友好
什么时候该放弃不规则数组?
它省空间,但不省维护成本。以下情况建议换方案:
- 需要频繁在某行中间插入/删除元素 →
int[][]不支持,必须手动复制,此时ArrayList<int></int>或ArrayList<arraylist>></arraylist>更合适; - 行数极多且每行极短(如百万行 × 平均2元素)→ 外层数组引用本身成为内存负担,考虑扁平化存储 + 索引映射;
- 涉及 JSON 序列化且服务端返回可能含
null行 → 部分库反序列化int[][]对null支持不稳定,改用对象封装更稳妥
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











