直接赋值arr2 = arr1不是拷贝,因二者共用堆中同一内存地址,修改arr2会同步影响arr1;真正拷贝需新建堆空间,如clone()、arrays.copyof()、system.arraycopy()或循环赋值,其中前两者对基本类型实现值复制,对引用类型仅复制引用(浅拷贝)。

Java 数组拷贝不是简单“复制变量”,而是涉及堆内存是否新开辟空间、元素如何复制的关键操作。真正独立的拷贝,必须让新数组在堆中拥有自己的连续内存块;否则只是共享地址,改一个就影响另一个。
为什么直接赋值 arr2 = arr1 不算拷贝?
因为 arr1 和 arr2 都是栈中的引用变量,它们存储的是同一个堆内存地址。数组本体(比如六个 int 值)只在堆里存一份。所以 arr2[2] = 9 实际上修改的是堆里那块共用区域,arr1 自然也看到变化。
四种常用拷贝方式的堆行为对比
• clone():为一维数组新建堆空间,基本类型数组完成值复制(真深拷贝),引用类型数组只复制引用(浅拷贝)
• Arrays.copyOf():本质是 new 新数组 + System.arraycopy,和 clone 效果一致,开发中更常用
• System.arraycopy():不创建新数组对象,需提前声明目标数组;它把源数组内容“搬”到目标数组的堆内存中,两个数组完全分离
• 循环赋值:手动逐个赋值,效果等同于 arraycopy,但代码冗长,仅适合特殊逻辑控制
引用类型数组拷贝要特别注意什么?
比如 String[] 或 Person[] 使用 clone 或 copyOf 后,新旧数组各占一块堆空间,但每个下标存的仍是原对象的地址。这意味着:
• 替换引用(如 copy[0] = new String("x"))不影响原数组
• 修改共享对象状态(如 copy[0].name = "Alice")会影响原数组对应位置——因为 Person 实例本身还在堆里同一处
• 对 String 这类不可变类,这种浅拷贝是安全的;对可变对象,若需彻底隔离,得递归深拷贝每个元素
内存开销其实很实在
• 新建数组会立即占用堆内存:基本类型按字节算(如 int[1000] ≈ 4KB),引用类型按引用大小算(64位 JVM 约 8 字节/元素)
• 不触发 GC,也不改变原数组的存活状态——只要还有任意引用指向它,它就不会被回收
• 大数组频繁拷贝会快速吃掉堆空间,尤其在循环或高并发场景下,需评估必要性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











