java数组内存管理核心是“栈存引用、堆存实体”:数组变量在栈中存地址,数组本体在堆中分配连续空间;数组是对象,由gc管理生命周期;赋值为引用传递,二维数组是“数组的数组”,各维独立分配堆内存。

Java 数组的内存管理机制,核心在于“栈存引用、堆存实体”,理解这点就抓住了本质。
数组变量在栈中,数组本体在堆中
声明一个数组变量,比如 int[] arr;,只是在栈内存中分配了一个引用类型的变量空间,初始值为 null。此时没有任何数组实体产生,也不占用堆内存。
只有执行初始化(如 arr = new int[5]; 或 int[] arr = {1,2,3};),JVM 才会在堆内存中开辟一块连续空间,用于存放 5 个 int 值,并把这块空间的首地址赋给栈中的 arr 变量。
简单说:栈里存的是“门牌号”,堆里才是“整栋房子”。
数组是对象,遵循对象内存规则
在 JVM 中,数组属于引用类型,是真正的对象——它有类信息(如 [I 表示 int 数组)、有长度属性(arr.length)、有继承自 Object 的方法(如 toString()、clone())。
因此,数组实例和普通对象一样,生命周期由垃圾回收器(GC)管理:当堆中的数组不再被任何栈变量或其它对象引用时,它就会在某次 GC 中被回收。
注意:int[] 和 Integer[] 都存在堆中,区别只在于前者存基本类型值,后者存对象引用。
数组初始化方式决定内存分配时机
- 动态初始化(new int[5]):明确指定长度,堆中分配固定大小连续空间,所有元素按类型赋予默认值(0、false、null 等)。
- 静态初始化({1,2,3}):编译器根据大括号内元素个数推断长度,同样在堆中创建数组并逐个赋值。
- 声明与初始化分离(int[] a; a = new int[3];):分两步完成,中间状态 a == null,访问 a[0] 会抛出 NullPointerException。
数组赋值本质是引用传递
执行 int[] b = a;,不是复制整个数组,而是把堆中同一块内存的地址再拷贝一份给 b。此时 a 和 b 指向同一个数组实体。
修改 b[0] = 99;,a[0] 的值也变成 99 —— 因为它们操作的是堆中同一位置的数据。
若需真正复制内容,必须手动遍历赋值,或使用 Arrays.copyOf()、clone() 等方法(注意:clone() 对一维数组是深拷贝,对二维数组仍是浅拷贝)。
二维数组是“数组的数组”
声明 int[][] matrix = new int[3][4];,实际在堆中创建了 1 个外层数组(长度为 3),其每个元素都是一个 int[] 引用;再为每个引用分配一个长度为 4 的内层数组。
这意味着:外层数组和每个内层数组各自独立占据堆内存,它们可以有不同的长度(即“不规则数组”),且每个内层数组可单独置为 null。
这种结构决定了二维数组的内存不是完全连续的,但每一行内部仍是连续的。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











