Java数组变量存地址、数据在堆,基本类型数组存数值,引用类型数组存地址;赋值和传参复制引用,多维数组是数组套数组。

Java 数组变量本身不存数据,只存地址;真正数据全在堆里——理解这点,才能分清“改内容”和“换数组”的区别,也才能避开 NullPointerException、共享修改、假扩容等常见坑。
数组变量在栈,数组对象在堆
声明 int[] arr; 时,只是在当前方法的栈帧里开一个引用槽位(4 或 8 字节),初始值为 null;执行 arr = new int[5]; 后,JVM 才在堆中分配一块连续内存,包含对象头、length 字段(4 字节)和 5 个 int 值,并把这块内存起始地址填进栈里的 arr 槽位。方法结束,栈帧销毁,arr 引用消失;若无其他引用指向该数组,它就成为 GC 候选。
基本类型数组 vs 引用类型数组:存的到底是什么?
两者对象都在堆上,但数据区内容不同:
-
基本类型数组(如
int[]、boolean[]):数据区直接存数值。例如new int[]{1,2,3},堆里就是连续三个整数。 -
引用类型数组(如
String[]、Object[]):数据区存的是地址(引用)。每个元素初始为null,赋值后才指向堆中其他位置的对象实例。比如String[] s = new String[2]; s[0] = "a";,堆中存在两个独立对象:一个是长度为 2 的数组,另一个是字符串"a"实例,s[0]存的是后者的地址。
赋值与传参:复制的是引用,不是数据
int[] b = arr; 或把数组作为参数传入方法,本质都是把栈中那个地址值拷贝一份——a 和 b 指向同一块堆内存。因此:
立即学习“Java免费学习笔记(深入)”;
- 通过
b[0] = 99修改元素,arr[0]立刻变成99; - 但执行
b = new int[10];,只是让b指向新数组,arr仍指向原数组; - 同理,方法内对形参数组元素的修改会影响实参,但给形参重新赋值不会改变实参指向。
多维数组:其实是“数组套数组”
Java 没有原生二维结构。int[][] matrix = new int[3][4]; 实际分两步:先建外层数组(长度 3,每个元素是 int[] 类型的引用),再为每个引用分别创建长度为 4 的一维数组。这意味着:
-
matrix[0]、matrix[1]、matrix[2]各自指向不同的堆内存块,彼此不要求连续; - 支持不规则长度,例如
int[][] jagged = new int[3][];后可分别赋jagged[0] = new int[2]; jagged[1] = new int[5];; - 访问
matrix[i][j]是两次解引用:先用i找到某行(即某个int[]引用),再用j在该行中定位元素。
不复杂但容易忽略。


















