System.arraycopy要求严格边界校验,调用前必须同时满足五条件:src与dest非null、srcPos和destPos非负、srcPos+length≤src.length、destPos+length≤dest.length、length≥0;否则抛ArrayIndexOutOfBoundsException或NullPointerException。

System.arraycopy 不会自动检查边界,所有校验必须由你提前完成。它只做一件事:按你给的数字,从源数组搬数据到目标数组——数字错,立刻崩。
必须同时满足的五个硬性条件
调用前这五项缺一不可,否则必抛 ArrayIndexOutOfBoundsException 或 NullPointerException:
- src ≠ null(源数组不能为 null)
- dest ≠ null(目标数组不能为 null)
- srcPos ≥ 0 且 srcPos + length ≤ src.length(源起始位置和长度不越界)
- destPos ≥ 0 且 destPos + length ≤ dest.length(目标起始位置和长度不越界)
- length ≥ 0(拷贝个数不能为负)
常见越界场景与对应检查方式
这些地方最容易漏判,尤其在动态计算索引时:
- 用变量算 srcPos(比如 i * 2),就得同步验证 i * 2 + length ≤ src.length,不能只验 i
- 源数组被截断或重建后,仍沿用旧的 length 值——必须重新确认当前可用长度
- 混淆 length 含义:它是“拷贝多少个”,不是“拷到第几个索引”,别和 destPos + length 混用
- dest 数组容量不足:比如 new int[5] 却想从索引 3 开始写 4 个元素(3 + 4 > 5),直接越界
安全封装建议(推荐复用)
避免每次调用都手写一堆 if,可统一收口校验逻辑:
public static void safeArrayCopy(Object src, int srcPos, Object dest, int destPos, int length) {
if (src == null || dest == null) throw new NullPointerException();
if (srcPos < 0 || destPos < 0 || length < 0)
throw new IndexOutOfBoundsException("negative index or length");
if (srcPos + length > Array.getLength(src) ||
destPos + length > Array.getLength(dest))
throw new IndexOutOfBoundsException("copy exceeds array bounds");
System.arraycopy(src, srcPos, dest, destPos, length);
}这样既保留 native 性能,又把风险控制在入口处。
类型兼容性不能忽略
即使所有索引都合法,类型不匹配也会失败:
- 基本类型数组严格区分:int[] → long[] 不行(不自动提升),int[] → int[] 才行
- 引用类型需满足赋值兼容:String[] 可拷到 Object[],但 Object[] 拷到 String[] 会抛 ArrayStoreException
- 泛型擦除后实际是 Object[],若目标数组是具体类型(如 Integer[]),运行时校验失败

















