system.arraycopy 仅在已有目标数组且类型兼容时实现高效物理迁移,适用于缓存复用、精确截取、数组内平移等场景;它不创建新数组,是浅拷贝,基本类型独立,引用类型共享对象。

System.arraycopy 能实现真正的物理迁移与备份,但前提是目标数组已分配且类型兼容;它不创建新数组,只做内存块搬运,所以“备份”必须手动 new 出目标数组,否则只是覆盖或位移。
什么时候该用 System.arraycopy 做迁移或备份
它不是万能拷贝工具,只在以下场景真正发挥价值:
- 已有目标数组(比如缓存池中预分配的 byte[]),只需把新数据“塞进去”——此时避免重复分配,省 GC 压力
- 需要精确控制拷贝起始位置和长度(如从网络包里截取 header 后 1024 字节到固定 buffer)
- 同一数组内做元素平移(如 ArrayList 删除中间元素后,把后续元素前挪:System.arraycopy(arr, i+1, arr, i, size-i-1))
- 多阶段处理中复用数组对象(例如解密→校验→压缩,每步都往同一 dest 数组不同偏移写入)
参数填错直接崩溃,五个值怎么对齐才安全
最常出问题的是 srcPos、destPos 和 length 的组合越界。记住三条硬规则:
-
srcPos ≥ 0且srcPos + length ≤ src.length,否则抛ArrayIndexOutOfBoundsException -
destPos ≥ 0且destPos + length ≤ dest.length,同上异常 - 源数组和目标数组组件类型必须兼容:
String[]可拷入Object[],但int[]拷入Integer[]会报ArrayStoreException
示例:想把 byte[] packet = {0x01,0x02,0x03,0x04,0x05} 的第 2~4 字节(即 0x02,0x03,0x04)备份到 byte[] backup = new byte[10] 的索引 3 开始处,应写:System.arraycopy(packet, 1, backup, 3, 3)。写成 srcPos=2 就漏掉第一个字节,写成 length=4 就越界。
基本类型 vs 引用类型:备份后改内容会不会互相影响
它永远是浅拷贝,但语义后果不同:
- 对
int[]、double[]这类基本类型数组:拷贝的是真实数值,源和目标完全独立,改一个不影响另一个 - 对
String[]、MyBean[]这类引用类型数组:拷贝的是对象引用地址,源数组和目标数组中相同位置指向同一个对象实例 - 这意味着:如果
MyBean是可变对象,你通过目标数组修改了backup[0].setName("xxx"),源数组里的packet[0]看到的也是新名字——这不是 bug,是浅拷贝的必然行为
真要深备份引用类型数组,得自己遍历 clone 或序列化,System.arraycopy 不负责这事。
别拿它当 Arrays.copyOf 用,否则白费性能
如果你只是想“把一个数组完整复制成新数组”,直接用 Arrays.copyOf(src, src.length) 更清晰;硬套 System.arraycopy 得先 new 目标数组,多写两行还容易漏判 null:
-
Arrays.copyOf内部确实调了System.arraycopy,但它封装了数组分配逻辑,语义明确 -
System.arraycopy的优势在于“已有目标数组”的复用场景;若每次都要new,它反而比Arrays.copyOf多一次手动检查和调用开销 - 小数组(比如拷贝
真正关键的不是“快”,而是“可控”——当你需要绕过封装、直控内存布局时,它才不可替代。其他时候,选更贴近意图的 API 才是稳妥做法。










