System.arraycopy是JVM层面的内存块搬运指令,非普通复制函数;它通过跳过字节码循环和逐元素校验实现高性能,但参数严格校验——src与dest不可为null,srcPos、destPos、length需满足边界条件,同数组移位时JVM自动选择正向或倒序搬运避免覆盖。

System.arraycopy 不是“复制函数”,而是 JVM 层面的内存块搬运指令。它快,是因为跳过了 Java 字节码循环和逐元素校验;它严,是因为五个参数任何一个越界或不兼容,立刻抛异常——没警告,没静默修复,全靠你写对。
五个参数各管什么
调用形式固定:System.arraycopy(src, srcPos, dest, destPos, length)
- src:源数组,不能为 null,否则直接抛 NullPointerException
- srcPos:从源数组哪个下标开始读,必须 ≥ 0 且 ≤ src.length;若 srcPos + length > src.length,立即抛 ArrayIndexOutOfBoundsException
- dest:目标数组,不能为 null,且组件类型必须与 src 兼容(int[] 不能往 long[] 拷,String[] 可往 Object[] 拷,但反过来不行)
- destPos:往目标数组哪个下标开始写,同样 ≥ 0,且 destPos + length ≤ dest.length,否则越界异常
- length:拷几个元素,可以是 0(合法空操作,用于快速校验边界),但不能为负(否则抛 NegativeArraySizeException)
同数组原地移位的关键逻辑
当 src 和 dest 是同一个数组时,就变成内存重排。JVM 会自动判断方向并选择正向或倒序搬运,避免覆盖——但前提是你的参数满足安全前提:
- 左移(destPos
- 右移(destPos > srcPos):比如把 arr[2..6] 移到 arr[5..9],写 System.arraycopy(arr, 2, arr, 5, 5) —— JVM 自动倒序搬,先处理高位再覆盖低位
- destPos == srcPos:相当于没动(length ≠ 0 时),length = 0 则只做参数校验,常用于预检边界是否合法
截取和拼接的实用写法
这不是语法糖,是两步地址搬运,每一步都得算准:
立即学习“Java免费学习笔记(深入)”;
- 截取一段:目标数组必须提前 new 好,长度至少等于 length。例如从 byte[] src 中取 offset=100 开始的 1024 字节:System.arraycopy(src, 100, dest, 0, 1024),前提是 100 + 1024 ≤ src.length
-
拼接两个数组:先算总长,再分段落位。int[] a 和 int[] b 拼成 result,写法是:
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length) - 常见错误:第二段 destPos 写成 0(b 覆盖 a)、或 result 长度少 1(越界崩溃)
性能真相与典型陷阱
它的快,是有条件的:
- 真正快的底层路径,依赖 JVM 调用 memmove 或 SIMD 指令,但前提是参数全合法——一旦抛出 ArrayStoreException 或 IndexOutOfBoundsException,根本没进复制逻辑,谈不上性能
- 基本类型数组拷贝的是值,引用类型数组拷贝的是地址(浅拷贝),别指望它深拷贝对象
- 不扩容、不新建数组、不触发 GC 写屏障,所以适合高频批量场景(如环形缓冲区滑动、删除后前移、IO buffer 重组)
- 多维数组可用,但只拷贝第一层引用(即拷贝的是子数组的引用,不是子数组内容)


















