数组对象本体在堆上且物理连续,含对象头、length字段和数据区;引用变量在栈中存地址,基本类型数组存值,引用类型数组存地址,传参时修改元素影响原数组,重赋数组引用则不影响。

数组对象本体在堆上,连续分配
Java中所有数组都是对象,创建时(如 new int[5])会在堆内存中开辟一块连续的、固定大小的空间。这块空间包含三部分:对象头(含GC标记、类元信息)、4字节的 length 字段、紧接着的原始数据区。比如 int[3] 实际占用约 12(对象头)+ 4(length)+ 3×4 = 28 字节,且这28字节是物理地址连续的。
引用变量在栈上,只存地址
声明语句 int[] arr; 本身不创建数组,只是在当前方法的栈帧里分配一个4或8字节的引用槽位(取决于JVM指针压缩),初始值为 null。执行 arr = new int[5]; 后,该槽位被填入堆中那块连续内存的起始地址。方法结束时,栈帧销毁,这个引用消失;若无其他引用指向该数组,它就进入垃圾回收队列。
基本类型 vs 引用类型数组:存的是什么?
两者都在堆上,但数据区内容不同:
- int[]、double[] 等:数据区直接存放数值,如 new int[]{1,2,3} → 堆中存的就是 1、2、3 这三个整数
- String[]、User[] 等:数据区存放的是引用值(即地址),每个元素可能是 null,也可能指向堆中其他位置的 String 或 User 对象
这意味着对 String[] s = new String[2]; s[0] = "a";,堆中其实有两处独立对象:一个是长度为2的数组对象,另一个是字符串 "a" 实例,s[0] 存的是后者的地址。
共享与修改:传参和赋值的本质区别
向方法传数组,传递的是引用的副本(即地址拷贝),所以:
- 修改 arr[i] = x → 影响原数组(因为操作的是同一块堆内存)
- 但执行 arr = new int[10] → 只改变形参引用所指的位置,原变量仍指向旧数组
同理,int[] a = b; 是让 a 和 b 指向同一块堆内存;后续通过 a 或 b 修改元素,对方立刻可见。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











