Java中数组引用本质是栈中存储地址的变量,指向堆中数组对象;数组变量存栈,数组本体在堆;引用类型数组元素存的是对象地址而非对象本身;传参和赋值传递的是地址副本;null表示引用未指向任何对象。

Java中数组引用的本质,就是栈中一个存放地址的变量,它指向堆里那个实实在在的数组对象。不是数据本身,也不是“对引用的引用”,而是一把通往堆内存的钥匙。
数组变量存栈,数组本体在堆
当你写 String[] names = new String[3];,JVM 做了两件事:
- 在栈中分配一个叫
names的变量,里面只存一个地址(比如0x7f8a1c),不存任何字符串 - 在堆中开辟一块连续空间,创建真正的数组对象——包含对象头、
length字段,以及 3 个初始为null的引用槽位
栈里的 names 消失(比如方法结束),只要还有别的变量指着堆里那个数组,它就不会被回收。
引用类型数组存的是“引用”,不是对象
String[] 或 Object[] 这类数组,堆中每个元素存的仍是地址,不是字符串或对象本身:
立即学习“Java免费学习笔记(深入)”;
-
names[0] = new String("Alice");→ JVM 在堆中新建字符串对象,再把它的地址写进names数组的第 0 个槽位 -
names[1] = names[0];→ 只是把同一个地址复制过去,两个槽位指向同一个字符串实例 -
names[2] = null;→ 第 3 个槽位清空,不再指向任何对象
所有槽位彼此独立,改一个不影响其他,也没有嵌套层级。
传参和赋值:传递的是引用的副本
数组作为参数传入方法,或用 = 赋给另一个变量,传递的都是栈中那个地址的拷贝:
-
int[] a = {1,2,3}; int[] b = a;→a和b都存着同一地址,修改b[0]就等于改a[0] -
void func(int[] arr) { arr[0] = 999; }→ 方法内改的是原数组内容,因为arr指向的还是那块堆内存 - 但
arr = new int[5];在方法内执行,只改变形参arr的指向,不影响外面的a
null 是引用的“空状态”,不是对象
String[] arr = null; 表示栈中这个变量没指向任何堆对象:
- 此时访问
arr.length或arr[0]会直接抛NullPointerException -
arr = new String[2];才真正分配堆空间,arr变量才有了有效地址 - 把已有的数组设为
null,只是切断栈变量与堆对象的联系;对象是否被回收,取决于是否还有其他引用指向它
不复杂但容易忽略。


















