System.arraycopy在重叠拷贝时天然安全,因其自动判别srcPos与destPos大小关系:若destPos > srcPos则倒序拷贝,否则顺序拷贝;且预先校验索引越界与类型兼容性。

System.arraycopy 在重叠拷贝场景下天然安全,根本原因在于它内部自动识别重叠关系,并按需切换复制方向——无需你手动判断或拆分逻辑。
它怎么知道该正着拷还是倒着拷?
底层会比较 srcPos 和 destPos 的大小关系:
- 如果 destPos > srcPos(目标起始位置在源起始位置右边),说明是“前向重叠”,JVM 自动从高索引往低索引倒序拷贝,避免未读数据被覆盖;
- 如果 destPos (目标起始位置在源左边),说明是“后向重叠”,则正序拷贝,安全无损;
- 如果相等,就是原地复制,直接跳过搬运(或做零长度处理)。
一个典型例子:数组内左移一位
比如想把 int[] arr = {1,2,3,4,5} 中索引 1~3(即元素 2、3、4)左移一位,覆盖到索引 0~2:
System.arraycopy(arr, 1, arr, 0, 3); // → arr 变成 {2,3,4,4,5}?错!实际是 {2,3,4,4,5}?不,正确结果是 {2,3,4,4,5}?等等——
不对。再看清楚:源区间是 [1, 3](含 3 个元素),目标从 0 开始。因 destPos(0) ,属后向重叠,JVM 正序执行:
→ 先拷 arr[1]→arr[0](2 覆盖 1),
→ 再拷 arr[2]→arr[1](3 覆盖 2),
→ 最后拷 arr[3]→arr[2](4 覆盖 3)。
结果为 {2,3,4,4,5} —— 这正是预期的左移效果,没有丢数据。
你不需要、也不应该绕开它去手动保护
有人误以为“重叠危险,得先复制到临时数组”,这反而引入额外内存分配和两次拷贝,拖慢性能且无必要:
- System.arraycopy 的重叠处理是 JVM 级别保障,和 C 的
memmove同级可靠; - 只要参数合法(索引不越界、数组非 null、类型兼容),结果一定语义正确;
- 手写循环模拟相同逻辑,极易出错(比如方向写反、边界算错),还失去向量化加速优势。
唯一要盯住的,是参数合法性
真正会出问题的不是重叠本身,而是越界或类型错误:
-
srcPos + length > src.length→ArrayIndexOutOfBoundsException; -
destPos + length > dest.length→ 同样抛异常; - 源是
String[],目标是Integer[]→ArrayStoreException。
这些检查在拷贝开始前就完成,不会让错误数据悄悄写入。

















