system.arraycopy()比for循环快是因为它是jvm内置本地方法,直接内存块拷贝,跳过字节码循环、逐元素边界检查及数组访问开销;但仅支持同类型数组间拷贝,不自动扩容,需预分配目标数组且参数顺序易错。

System.arraycopy() 为什么比 for 循环快
因为它是 JVM 内置的本地方法,直接调用底层 memcpy 或类似指令,绕过了 Java 字节码循环、边界检查和数组访问开销。普通 for 循环每次读写都要查数组长度、做索引校验;而 System.arraycopy() 把整块内存当“黑盒”搬走,只要源/目标类型兼容、范围合法,就一次性完成。
注意:它不支持跨类型拷贝(比如 int[] 到 long[]),也不做自动装箱/拆箱——这点常被误以为是“通用复制工具”,其实不是。
正确调用 System.arraycopy() 的四个参数顺序
签名是 System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)。最容易错的是前两个参数位置:源数组在前,源起始索引紧随其后;很多人写反成 srcPos, src,编译不过但 IDE 提示不明显,尤其在重构时手滑。
-
src和dest必须是数组引用,不能是基本类型值或 null(否则抛NullPointerException) -
srcPos和destPos是从 0 开始的索引,负数直接抛IndexOutOfBoundsException -
length是要拷贝的元素个数,不是结束索引;如果srcPos + length > src.length,同样抛异常
示例:System.arraycopy(src, 2, dest, 0, 3) 表示把 src[2]、src[3]、src[4] 拷到 dest[0]~dest[2]。
数组类型匹配与运行时检查
编译期只检查引用类型兼容性,实际执行时才做元素类型校验。例如把 String[] 拷到 Object[] 没问题(子类→父类),但反过来会抛 ArrayStoreException。
基本类型数组之间完全不兼容:int[] 不能拷到 long[],哪怕长度一致也不行——JVM 不做隐式转换。若真需要转,得用 Arrays.stream().mapToInt() 等方式,但性能损失巨大。
- 同类型数组(如
int[] → int[]):最快,纯内存搬运 - 对象数组子类→父类(如
ArrayList[] → List[]):允许,但目标数组运行时类型必须能容纳源元素 - 任意跨类型基本数组:禁止,编译不报错但运行时报
ArrayStoreException
性能陷阱:小数组反而更慢?
对极小数组(比如长度 ≤ 4),System.arraycopy() 的 JNI 调用开销可能超过简单赋值。HotSpot 在某些版本会对超小拷贝做内联优化,但不可依赖。
更隐蔽的问题是「重叠拷贝」:当源和目标是同一数组,且区间有交集时,System.arraycopy() 按照从头到尾顺序搬,可能导致中间结果被覆盖。例如:System.arraycopy(arr, 0, arr, 1, 3) 本意是右移,但实际会把 arr[0] 覆盖进 arr[1],再用已改的 arr[1] 覆盖 arr[2]……结果错误。此时应改用 Arrays.copyOfRange() 或手动倒序拷贝。
真正影响性能的关键其实是 GC 压力:避免频繁分配临时数组。如果只是想截取一段,优先用 Arrays.copyOfRange()(它内部也调 arraycopy,但封装了 new 数组逻辑);如果目标数组已存在且复用,才直接上 System.arraycopy()。










