System.arraycopy参数错序会静默覆盖目标数组,不校验类型兼容性;Arrays.copyOf自动分配新数组但需指定泛型类型避免Object[],二者均为浅拷贝且性能相近。

System.arraycopy 用错参数顺序会静默出错
这个方法不校验源数组和目标数组的类型是否兼容,只在运行时检查索引越界。如果把 srcPos 和 destPos 写反,或者漏算长度,结果就是目标数组部分元素被意外覆盖,而编译器完全不报错。
典型错误场景:从一个 int[] 复制前 3 个元素到另一个同长数组,却写成:
System.arraycopy(src, 0, dest, 3, 3); // 错!destPos=3 导致写入位置偏移
正确写法要确保目标起始位置合理,且 length 不超边界:
-
src和dest可以是同一数组(实现移动或覆盖),但需注意重叠时的行为(按从左到右复制) - 如果
src是Object[],dest是子类数组(如String[]),运行时抛ArrayStoreException - 它不创建新数组,只拷贝内容,所以必须提前分配好
dest,否则空指针
Arrays.copyOf 本质是封装了 new + arraycopy
它比 System.arraycopy 多做一件事:自动分配新数组。内部逻辑等价于先 new 一个指定长度的目标数组,再调 System.arraycopy 拷贝(源长度不足时补默认值,超出则截断)。
立即学习“Java免费学习笔记(深入)”;
常见误用点:
- 传入负长度 → 抛
NegativeArraySizeException,不是IllegalArgumentException - 原数组为
null→ 直接返回null,不会抛空指针(这点常被忽略) - 泛型擦除后,
Arrays.copyOf(T[], int, Class<? extends T[]>)才能生成正确类型的数组,普通copyOf对引用类型返回Object[]
例如想复制 String[] 得到 String[],不能只用 Arrays.copyOf(arr, len),得写:
String[] copy = Arrays.copyOf(original, newLength, String[].class);
性能差异只在「是否新建数组」这一层
两者底层都走 JVM 的内存块拷贝(类似 C 的 memmove),速度几乎一样。真正影响性能的是你是否需要新数组。
- 如果已有目标数组且复用频繁(比如缓冲区循环写入),用
System.arraycopy避免 GC 压力 - 如果每次都要新数组,
Arrays.copyOf更简洁,少写两行代码,也少一个出错点 - 对基本类型数组,JVM 可能进一步优化为 CPU 级别指令;但对象数组始终是逐引用拷贝,不存在“深拷贝”
没有所谓“更快”的 API,只有更贴合你内存管理意图的那个。
数组复制 ≠ 对象克隆
无论用哪个方法,都只是浅拷贝:对象数组里存的是引用,复制后两个数组指向同一堆对象。改其中一个数组里的对象状态,另一个“看到”的是一样的。
- 需要深拷贝?得自己遍历 +
clone()或序列化,或用第三方库(如 Apache Commons Lang 的SerializationUtils.clone) - 多维数组更要小心:
int[][]用copyOf只复制了外层数组,内层数组引用没变 - 不可变数组(如
ImmutableList)根本不能靠这些方法“复制”,它们的语义和实现完全不同
别被“复制”这个词带偏——它只管内存里那几块字节怎么搬,不管业务上你要的是“副本”还是“镜像”。









