System.arraycopy仅支持浅拷贝,深拷贝需配合手动创建新对象及逐层复制:多维数组须逐行新建并复制;对象数组需克隆元素;基本类型和String数组因不可变性可直接使用。

System.arraycopy 本身不能直接实现深拷贝,它只做浅拷贝——即复制数组元素的值(基本类型)或引用(对象/子数组),不递归复制被引用的对象内容。所谓“深拷贝技巧”,其实是用它作为高效搬运工具,配合手动逻辑完成真正的深拷贝。
下面分场景讲清楚怎么用、为什么这么用、以及关键避坑点:
多维数组的深拷贝:逐层用 arraycopy 搬数据
二维 int[][] 是最典型例子。arraycopy 可以高效复制每行的 int 元素,但必须自己分配新行数组:
int[][] src = {{1, 2, 3}, {4, 5}};
int[][] dst = new int[src.length][];
for (int i = 0; i < src.length; i++) {
dst[i] = new int[src[i].length]; // 新建每一行
System.arraycopy(src[i], 0, dst[i], 0, src[i].length); // 搬数值,安全
}✅ 这样 dst[0][0] = 99 不会影响 src[0][0]
❌ 错误写法:System.arraycopy(src, 0, dst, 0, src.length) → 只复制了行引用,dst[0] == src[0]
注意:若子数组里存的是可变对象(如
Person[]),那arraycopy仍只复制引用,你还得对每个dst[i]再调clone()或构造新实例。立即学习“Java免费学习笔记(深入)”;
一维对象数组的深拷贝:先搬引用,再克隆元素
假设 Person 正确实现了 clone():
Person[] src = {new Person("Alice"), new Person("Bob")};
Person[] dst = new Person[src.length];
System.arraycopy(src, 0, dst, 0, src.length); // 快速复制引用
for (int i = 0; i < dst.length; i++) {
dst[i] = dst[i].clone(); // 真正分离对象状态
}⚠️ 如果 Person 没重写 clone(),或字段含可变对象(如 List<Address>),clone() 本身也只是浅拷贝,需进一步处理。
String[] 和基本类型数组:无需深拷贝,“伪深”即可用
-
int[]、double[]等:arraycopy复制的是数值,天然隔离,直接用。 -
String[]:虽然arraycopy复制的是引用,但String不可变,改dst[i] = "new"不影响src[i];即使dst[i].replace(...)也返回新对象,原引用不变。
所以这类数组用 arraycopy 就等于得到了行为上等价于深拷贝的效果。
深拷贝不是 arraycopy 的责任,而是你的设计责任
arraycopy 的角色是:
- 在已知结构的前提下,高速搬运连续内存块(比如一整行 int、一个 byte[] 片段)
- 它不识别“对象是否可变”,也不关心“子数组要不要新建”
真正决定是否深拷贝的,是你对数据语义的理解:
- 这个数组将来会不会被多处修改?
- 子元素是不是共享状态?
- 修改副本是否允许影响源头?
只要答案是“否”,你就得绕过 arraycopy 的浅层限制,主动创建新容器 + 用 arraycopy 填充底层数据。
不复杂但容易忽略


















