System.arraycopy重叠拷贝天然安全,因其JVM在调用前完成全部校验并自动适配拷贝方向:destPos>srcPos时倒序、destPos<srcPos时正序、相等则跳过,语义等同memmove;崩溃只源于参数非法(如越界、null、类型不兼容),而非重叠本身。

System.arraycopy 的内存安全性不靠“额外保护”,而靠 JVM 在调用前就完成全部校验,并在底层自动适配拷贝方向——它本身就是为重叠场景设计的,不是凑巧能用。
重叠拷贝天然安全,靠的是方向自适应
当 src 和 dest 是同一个数组、区间有交集时,JVM 不会报错,而是根据 srcPos 与 destPos 的大小关系 决定搬运顺序:
- destPos > srcPos(目标起始在源起始右边)→ 倒序拷贝(从高索引往低索引),避免未读数据被覆盖
- destPos < srcPos(目标起始在源起始左边)→ 正序拷贝,防止已写区域干扰后续读取
- destPos == srcPos → 直接跳过,或做零长度处理
这和 C 的 memmove 行为一致,不是模拟,是同等语义的原生实现。
真正会崩的,从来不是重叠,而是参数非法
所有崩溃都发生在拷贝开始前,JVM 一次性做完全部检查,不给错误数据写入的机会:
- src 或 dest 为 null → NullPointerException
- length 为负 → NegativeArraySizeException
- srcPos、destPos 越界,或 srcPos + length > src.length → ArrayIndexOutOfBoundsException
- 源数组类型无法赋值给目标数组(如 String[] 拷到 Integer[])→ ArrayStoreException
不用临时数组,也不用手动拆分
有人担心重叠危险,于是先复制到临时数组再搬回——这反而引入两次拷贝+一次内存分配,拖慢性能且无必要:
- System.arraycopy 的重叠处理是 JVM 级保障,比手写循环更可靠
- 手写容易方向写反、边界算错,还失去向量化加速机会
- 只要参数合法,结果一定语义正确;出问题一定是参数错了,不是重叠本身的问题
多线程下唯一要注意的是写共享
单次 arraycopy 调用是原子的,但不提供线程安全保证:
- 多个线程往同一 dest 数组不同区域写,可能因 CPU 缓存不同步导致数据撕裂
- 推荐每个线程操作独立 buffer,最后用一次 arraycopy 合并
- 或采用“新数组 + AtomicReference.lazySet”方式替换引用,避免并发写冲突

















