数组拷贝需依场景选方法:原地移位用system.arraycopy,扩容截断用arrays.copyof,独立副本基本类型用clone()、引用类型注意浅拷贝,部分拷贝到已有数组必用arraycopy;小数据量直接赋值更优,同数组右移自动倒序;所有内置拷贝均为浅拷贝,深拷贝需手动或工具实现。

数组拷贝不是“复制完就完事”的操作,而是涉及内存模型、性能临界点和语义安全的关键环节。重构与优化的核心,不在于换一个方法,而在于让拷贝行为精准匹配场景意图——是原地重排、扩容截断、还是不可变快照?
明确拷贝意图,再选方法
不同意图对应不同底层机制,强行统一用一种方式反而引入冗余或风险:
-
需要原地移位(如删除后前移、环形缓冲区滚动):必须用
System.arraycopy,且 src 和 dest 为同一数组。其他方法无法实现地址级平移,只能新建数组再赋值,徒增 GC 压力。 -
需要扩容或截断长度:优先用
Arrays.copyOf。它内部调用arraycopy,但自动分配目标数组,省去手动 new 的步骤,语义更清晰。 -
仅需一份独立副本,无长度变更:对基本类型数组,
clone()最简洁;对引用类型,注意它仍是浅拷贝,嵌套对象未分离。 -
只拷某一段,且目标数组已存在:
System.arraycopy是唯一支持部分拷贝到已有数组指定位置的方法,copyOfRange返回新数组,不适合复用缓冲区场景。
避开 arraycopy 的隐形陷阱
System.arraycopy 快,但快得有前提。忽略这些细节,可能比 for 循环还慢:
- 拷贝长度 ≤ 16 时,JNI 调用开销常高于纯 Java 循环。建议小数据量(如配置项、临时标记数组)走 if 分支,直接赋值。
- srcPos 或 destPos 超出数组边界,或 length 导致越界,会立即抛
ArrayIndexOutOfBoundsException。不要依赖 try-catch 捕获——应提前校验srcPos + length ≤ src.length等条件。 - 同数组拷贝时,若 destPos srcPos(右移),自动倒序执行。无需手动写两个分支,传参正确即可。
避免浅拷贝误用导致的隐性共享
Java 中所有内置数组拷贝(包括 clone、arraycopy、copyOf)都是浅拷贝。对一维基本类型数组没问题,但对 Object[] 或二维数组,元素引用仍指向原对象:
- 例如
String[][] grid = new String[3][3],用grid.clone()后,新数组的每行仍指向原数组的同一行对象。修改newGrid[0][0] = "X"不影响原数组,但newGrid[0] = new String[]{"Y"}才真正隔离。 - 若业务要求完全独立副本(如状态快照、多线程读写隔离),需自行递归深拷贝,或使用
SerializationUtils.clone()(Apache Commons)等工具,但注意序列化开销。
性能敏感场景的组合策略
高频、大数据量拷贝(如网络包解析、图像像素处理)需组合使用:
- 预分配目标数组,避免多次扩容。例如批量处理固定大小帧数据,复用同一
byte[] buffer,每次用arraycopy覆盖内容。 - 对超长数组,考虑分块搬运(如每 8KB 一组),减少单次 JVM 内存扫描压力,也利于 CPU 缓存局部性。
- 避免在循环内反复调用
Arrays.copyOf,它每次新建数组。应先计算最终所需长度,一次性分配,再用arraycopy拼接各段。











