system.arraycopy是java中性能最优的数组拷贝方式,因其直接调用jvm底层native方法,对基本类型编译为cpu内存块指令,对引用类型跳过写屏障,并避免java层循环开销。

System.arraycopy 是 Java 中性能最优的数组拷贝方式,它直接调用 JVM 底层的本地方法(Native Method),绕过 Java 层的边界检查和循环逻辑,在字节码层面实现内存块的高效复制。理解它的行为和限制,比单纯记住“它快”更重要。
System.arraycopy 的核心参数与语义
调用形式为:System.arraycopy(src, srcPos, dest, destPos, length)。五个参数必须全部合法,否则抛出 ArrayStoreException 或 ArrayIndexOutOfBoundsException。
- src 和 dest 必须是同类型数组(如 int[] → int[],String[] → String[]),但不要求是同一实例;若类型不兼容(如 Object[] ← String[]),运行时才报错
- srcPos 和 destPos 是起始索引,从 0 开始,需满足:0 ≤ srcPos ≤ src.length 且 0 ≤ destPos ≤ dest.length
- length 是要复制的元素个数,必须 ≥ 0;若 length > 0,则要求 srcPos + length ≤ src.length 且 destPos + length ≤ dest.length,否则抛异常
为什么它比 for 循环快?——不只是“底层调用”
System.arraycopy 的优势不仅来自 Native 实现,更在于 JVM 的深度优化:
- 对基本类型(int、long 等)常被 JIT 编译为 CPU 的内存块复制指令(如 x86 的
rep movsd),单条指令完成多元素搬运 - 对引用类型,JVM 可跳过逐个赋值的 write barrier(写屏障)开销,在安全前提下批量处理(尤其在 G1/CMS 等 GC 下有专门优化路径)
- 避免 Java 层循环的栈帧压入、计数器维护、每次访问的数组边界检查(虽然 HotSpot 会做部分消除,但无法 100% 消除)
常见误用场景与避坑指南
看似简单的方法,实际使用中容易踩坑:
-
目标数组未初始化或长度不足:dest 必须是已分配的对象,且 destPos + length 不得越界。错误示例:
int[] dst = new int[5]; System.arraycopy(src, 0, dst, 3, 10);→ 报 ArrayIndexOutOfBoundsException - 源/目标为 null:任一参数为 null,立即抛 NullPointerException,不会等到复制阶段
-
跨维数组误用:二维数组如
int[][]是“数组的数组”,System.arraycopy 只复制引用(即浅拷贝),不会递归复制子数组。若需深拷贝,必须手动遍历或使用其他工具 - 并发修改风险:该方法不加锁,若 src 或 dest 在拷贝过程中被其他线程修改,结果不可预测。多线程环境下需自行同步
替代方案对比:何时不该用 System.arraycopy?
不是所有场景都适合它:
- 小数组(≤ 16 元素):现代 JVM 对简单 for 循环做了极致优化,差距可忽略;此时代码可读性(如 Arrays.copyOf)更重要
- 需要类型转换或过滤:比如 int[] → Integer[],System.arraycopy 无法完成,应使用 Stream 或传统循环
-
目标容器非数组:如拷贝到 ArrayList,应优先用
list.addAll(Arrays.asList(...))或构造器,而非先新建数组再拷贝 - 需要默认值填充或截断逻辑:Arrays.copyOf 更简洁,它内部也调用 System.arraycopy,但封装了扩容/截断逻辑
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











