Java中声明初始化不规则二维数组需先声明int[][] arr = new int[3][],再逐行分配如arr[0] = new int[2];或一步初始化int[][] arr = {new int[2], new int[5], new int[1]}。

Java 里怎么声明和初始化一个不规则二维数组
Java 没有原生“二维数组”类型,int[][] 实际是「一维数组的数组」——每个元素都是一个独立的 int[] 引用。所以不规则(锯齿)结构不是特例,而是默认行为。
常见错误是试图用 new int[3][4] 初始化后,再改某一行长度:这不行,因为 new int[3][4] 创建的是规则矩形数组,每行固定 4 个元素,后续无法缩放或扩容该行引用指向的数组对象。
- 正确做法:先声明
int[][] arr = new int[3][];(只分配外层数组,内层全为null) - 再逐行初始化:
arr[0] = new int[2]; arr[1] = new int[5]; arr[2] = new int[1]; - 也可以一步到位:
int[][] arr = { new int[2], new int[5], new int[1] };
访问锯齿数组时 NullPointerException 怎么来的
因为内层数组是手动分配的,漏掉某一行初始化(比如只做了 arr[0] 和 arr[2]),访问 arr[1][0] 就会触发 NullPointerException——arr[1] 是 null,不是空数组。
这不是语法错误,编译能过,运行才崩。尤其在循环遍历中容易忽略判空:
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 安全遍历必须检查
if (arr[i] != null)再进内层循环 - 不要假设
arr.length和arr[i].length都一定存在 - 工具类如
Arrays.toString(arr[i])对null元素会直接抛异常,不能无脑用
锯齿数组和 ArrayList> 的内存与性能差异
两者都能表达不规则结构,但底层完全不同:int[][] 是连续堆内存块(每行各自连续),而嵌套 ArrayList 是三层对象引用(外层 List → 内层 List → Integer 对象),开销大得多。
影响很实际:
- 原始类型(
int[][])无自动装箱,存取快;ArrayList<ArrayList<Integer>>每次 get/set 都要拆箱/装箱 -
int[][]内存局部性好,CPU 缓存友好;嵌套 List 各自散落在堆上 - 但如果需要频繁增删行或列,
int[][]不支持动态调整,必须手动System.arraycopy或重建,此时ArrayList更灵活
序列化和 JSON 转换时的隐含问题
JSON 库(如 Jackson、Gson)通常能正常序列化 int[][] 成嵌套数组,但反序列化时可能出错:如果 JSON 是 [[1,2],[3,4,5]],Jackson 默认能映射到 int[][];但如果 JSON 里某一行是 null(如 [[1,2],null,[3]]),反序列化后对应行就是 null,后续访问极易 NPE。
更隐蔽的是 Gson 默认不保留空行信息——如果某行初始化为 new int[0],它序列化成 [],但反序列化回来仍是 int[0];而 null 行会被跳过或报错,取决于配置。
- 写 JSON 时,明确用
new int[0]代替null表示“空但存在”的行 - 用 Jackson 可配
DeserializationFeature.ACCEPT_NULL_AS_EMPTY_ARRAY来缓解 - 别依赖 JSON 字符串结构去推测内存是否连续——它只是文本表示

















