System.arraycopy() 比 for 循环快因其是 JVM 底层 C/C++ 实现的本地方法,直接内存块拷贝,省去字节码循环、逐元素检查等开销,且不自动扩容、仅支持数组间兼容类型拷贝。

System.arraycopy() 为什么比 for 循环快
因为它是 JVM 底层用 C/C++ 实现的本地方法,直接操作内存块,跳过了 Java 字节码循环、边界检查(在调用时已由 JVM 一次性校验)、对象引用逐个赋值等开销。不是“语法糖”,是真正意义上的零拷贝(同地址空间内)。
常见错误现象:ArrayStoreException 或 IndexOutOfBoundsException 被误以为性能问题——其实根本没跑进复制逻辑,是参数校验失败就抛出了。
- 只适用于数组到数组,不支持 Collection 或 Stream
- 源数组和目标数组必须是兼容类型(如
Object[]→String[]会抛ArrayStoreException) - 不会自动扩容:目标数组必须预先分配好足够空间
五个参数怎么填才不越界
签名是 System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)。最容易错的是后三个参数组合导致越界——JVM 检查的是「srcPos + length ≤ src.length」且「destPos + length ≤ dest.length」,不是单看 length 是否超源/目标长度。
使用场景:从 List 转数组、分片拷贝、合并两个数组前半段。
立即学习“Java免费学习笔记(深入)”;
-
srcPos和destPos可为 0,但不能为负 -
length必须 ≥ 0;等于 0 是合法空操作,不会抛异常 - 若想拷贝整个源数组到目标数组开头,别写
length = src.length后再手动算dest.length,应先确保dest.length >= src.length
示例:System.arraycopy(src, 2, dest, 0, 3) 表示从 src[2] 开始取 3 个元素,放到 dest[0] 起——实际访问的是 src[2]、src[3]、src[4]。
基本类型数组 vs 引用类型数组的区别
行为一致,但语义不同:基本类型(如 int[])复制的是数值本身;引用类型(如 String[])复制的是引用地址,不是对象内容。这点和 Arrays.copyOf() 完全一样,别误以为 arraycopy 会深拷贝。
性能影响:基本类型复制更快(纯内存搬移),引用类型多一次指针写入,但差距微乎其微;真正的瓶颈从来不在这里,而在 GC 压力或缓存行失效。
- 不要用它来“克隆”对象数组并以为得到了新对象——
dest[i] == src[i]仍为true - 多维数组(如
int[][])只能复制第一层引用,即复制的是子数组的引用,不是子数组内容 - 如果目标数组是
final字段,arraycopy仍可修改其元素——final仅限制引用不可变,不约束内容
替代方案对比:什么时候不该用 System.arraycopy()
当你要复制并转换类型(如 int[] → Integer[])、过滤元素、或需要流式处理时,System.arraycopy() 直接失效。它只做裸数据搬移,没有逻辑扩展能力。
容易踩的坑:Arrays.copyOf() 看似更方便,但它内部就是封装了一次 arraycopy + 新数组分配;而 clone() 对一维数组也调用 arraycopy,但对多维数组只浅拷贝第一层——这些细节不看源码很容易误判。
- 要扩容+复制?用
Arrays.copyOf()更安全(自动处理新数组创建) - 要并发安全地复制某段?
arraycopy本身线程安全,但需确保源/目标数组不被其他线程同时写入 - Android 低版本(API arraycopy 对大数组可能触发 JIT 编译延迟,实测反而比简单循环慢——这种边缘 case 得压测验证
真正复杂的点从来不是函数怎么写,而是你是否清楚自己要的到底是“位拷贝”“引用拷贝”还是“语义拷贝”。arraycopy 只提供第一种。









