system.arraycopy本身不校验参数,但执行前严格检查五项边界:src/dest非null、srcpos/destpos≥0、length≥0、srcpos+length≤src.length、destpos+length≤dest.length,任一不满足立即抛异常;类型还需兼容,否则抛arraystoreexception。

System.arraycopy 本身不校验参数,但会在执行前做严格检查——只要任一条件不满足,立刻抛异常,不沉默、不修复、不兜底。它的“安全”不是容错,而是明确报错;它的“性能”不是靠省略检查,而是把所有检查压缩到一次完成,之后直接走底层内存指令。
必须手动确保的五项边界
调用前你得自己确认以下全部成立,JVM 不替你算:
- src 和 dest 都不能为 null,否则抛 NullPointerException
- srcPos ≥ 0 且 srcPos + length ≤ src.length
- destPos ≥ 0 且 destPos + length ≤ dest.length
- length ≥ 0(length == 0 合法,不搬运但会完成全部校验)
- 源与目标数组组件类型兼容:int[] ↔ long[] 不行;String[] → Object[] 可以;Object[] → String[] 运行时报 ArrayStoreException
校验不是可选项,是调用前提
它不像 Collections.copy 或 Arrays.copyOf 那样内置防护逻辑。你传进去什么,它就信什么。比如:
- srcPos = -1 → 直接 ArrayIndexOutOfBoundsException
- srcPos = 5, length = 10, src.length = 8 → 5 + 10 = 15 > 8 → 立即崩
- 想把 byte[] 拷进 char[] → 类型不兼容 → ArrayStoreException
这些都不是运行中出错,而是在进入 native 方法前就被拦截。所以真正“安全”的写法,是把校验收口在调用之前,而不是依赖 arraycopy 自己兜底。
为什么校验完还能快?
因为所有边界检查只做一次,在 Java 层入口完成;之后 JVM 直接跳转到高度优化的 native 实现(如 memmove),不再逐元素判界、不触发 GC 写屏障、不走字节码解释路径。小数组可能被 JIT 内联成几条 CPU 指令,大数组则启用 SIMD 或多路 prefetch —— 这些加速的前提,正是你已保证参数合法。
推荐封装一个带校验的工具方法
避免每次调用都重复写 if 堆叠,也防止漏判:
public staticif (src == null || dest == null) throw new NullPointerException();
if (srcPos if (srcPos + length > src.length || destPos + length > dest.length) {
throw new ArrayIndexOutOfBoundsException("copy out of bounds");
}
System.arraycopy(src, srcPos, dest, destPos, length);
}
这样既守住安全底线,又保留了原生性能。调用时只需一行,不用再担心哪项漏了。











