Java数组是对象,存于堆中,变量存地址;赋值传参仅复制引用;多维数组是数组套数组,支持不规则长度;length为final字段;数组长度不可变但引用可重定向。

Java 中的数组本质是对象,所以它天然属于引用类型——变量本身不存数据,只存地址;真正数据全在堆里。理解这点,才能搞清赋值、修改、传参时为什么“改一个,另一个也变”,也才能明白多维数组为什么能“每行长度不同”。
数组变量和数组对象分处栈与堆
声明 int[] arr; 时,只是在栈里开了个“空盒子”,里面装着 null;执行 arr = new int[5]; 后,JVM 才在堆中划出一块连续内存,存放对象头、length 字段和 5 个 int 值,再把这块内存的起始地址填进栈里的那个“盒子”。后续所有对 arr 的操作,其实都是通过这个地址去堆里读写。
关键细节:
- 基本类型数组(如 int[])在堆中直接存数值;引用类型数组(如 String[])在堆中存的是对象地址,那些 String 对象本身还在堆的其他位置
- arr.length 是每个数组对象自带的 final 字段,存在对象数据区开头,不是方法调用,也不可修改
- 赋值语句 int[] b = arr; 只复制地址,b 和 arr 指向同一块堆内存,改 b[0] 就等于改 arr[0]
多维数组就是“数组套数组”
Java 没有原生的二维结构,所谓 int[][] matrix,其实是“一个装着 int[] 引用的数组”。执行 new int[3][4] 时,分两步:先创建外层数组(长度为 3,每个元素是 int[] 类型的引用),再为这 3 个引用分别分配长度为 4 的一维数组。
立即学习“Java免费学习笔记(深入)”;
这意味着:
- 外层数组的三个元素(matrix[0]、matrix[1]、matrix[2])各自指向不同的堆内存块,彼此不要求连续
- 可以不规则初始化,比如 int[][] jagged = new int[3][]; 后,单独给每行赋不同长度:jagged[0] = new int[2]; jagged[1] = new int[5]; jagged[2] = new int[1];
- 访问 matrix[i][j] 实际是两次解引用:先用 i 找到某一行(即某个 int[] 引用),再用 j 在该行中定位具体元素
数组长度不可变,但引用可重定向
数组一旦用 new 创建,其 length 就固定了,无法扩容或缩容。但这不代表不能“换内容”——你可以让数组变量指向一个全新的数组对象。
例如:
- int[] a = {1, 2, 3}; → a 指向堆中长度为 3 的数组
- a = new int[]{4, 5, 6, 7}; → a 现在指向另一个长度为 4 的新数组,原数组若无其他引用,会被 GC 回收
- 这种重定向不影响其他仍持有旧引用的变量,比如 int[] b = a; 之后再执行上面那句重定向,b 仍指向原来的 {1,2,3}
遍历与越界:下标必须落在 [0, length−1] 范围内
无论一维还是多维,所有元素访问都依赖下标。一维数组合法范围是 0 到 arr.length - 1;二维数组则需同时满足 i 且 j 。漏判任一条件,运行时就会抛出 ArrayIndexOutOfBoundsException。
安全遍历建议:
- 一维:用 for (int i = 0; i
- 二维:外层循环用 i ,内层用 j ,尤其适用于不规则数组
- 避免硬编码数字,比如不用 i ,而始终依赖 .length 属性


















