Java数组拷贝易踩坑的根本原因是未理解内存机制:变量存栈中地址,数据存堆中;arr2 = arr1仅为引用复制,真正拷贝需在堆中新开空间,常用Arrays.copyOf、System.arraycopy、clone或循环赋值实现。

Java里数组的“拷贝”容易踩坑,根本原因不在代码写法,而在没看清内存里到底发生了什么。变量名只是个标签,真正存数据的是堆里的连续空间;所谓“复制”,本质是地址怎么传、空间怎么开。
数组变量存在栈里,实际数据在堆中
写 int[] arr = {1, 2, 3} 这行时,arr 本身存在栈中,它不存数字,只存一个十六进制地址(比如 0x7a8b);真正的 {1, 2, 3} 是连续放在堆里的三块 int 大小的空间。栈快但小,堆大但要 GC 管理。
所以,只要没新开堆空间,就谈不上真正拷贝。
arr2 = arr1 是纯引用复制,不是拷贝
这行代码只做了一件事:把 arr1 栈里存的那个地址,原封不动抄给 arr2。两个变量指向堆中同一段内存。
立即学习“Java免费学习笔记(深入)”;
- 修改 arr2[0] = 9,其实是改堆里第一个位置的值
- 再读 arr1[0],自然也是 9 —— 因为读的是同一个地址
- 这不是 bug,是设计:省空间、速度快,适合只读或共享场景
真拷贝必须在堆里新开一块连续空间
要让两个数组互不影响,就得让 arr2 指向堆里另一段新分配的、内容相同的内存。常用方式有四种:
- Arrays.copyOf(arr1, arr1.length):最常用,内部调用 System.arraycopy,高效安全
- System.arraycopy(src, 0, dst, 0, len):底层 C 实现,性能最优,需提前创建目标数组
- arr1.clone():返回新数组,但注意它仍是浅拷贝——对基本类型数组没问题,对象数组仍共享元素引用
- 手动循环赋值:逻辑清晰,适合教学或特殊逻辑,但性能略低
对象数组还要分清浅拷贝和深拷贝
基本类型数组(如 int[])拷贝完就彻底隔离了。但对象数组(如 Person[])不同:
- 上面四种方式都只做浅拷贝:新数组是新的,但每个 Person 元素仍是原对象的引用
- 改 arr2[0].setName("Tom"),arr1[0] 的名字也会变
- 要彻底隔离,得递归克隆每个对象——即深拷贝,通常靠序列化、JSON 工具或手动重写 clone 方法实现


















