system.arraycopy 的正确使用取决于五个参数的语义边界和运行时约束:src/dest 非 null;srcpos、destpos ≥ 0;srcpos + length ≤ src.length;destpos + length ≤ dest.length;length ≥ 0。

System.arraycopy 是 Java 中高效拷贝数组的底层方法,但用错参数极易引发 ArrayIndexOutOfBoundsException、数据覆盖、静默截断等隐蔽问题。关键不在“会不会用”,而在“是否理解每个参数的语义边界和运行时约束”。
参数含义必须逐个对齐真实内存状态
其签名 System.arraycopy(src, srcPos, dest, destPos, length) 中五个参数相互制约,任一错配都会出错:
-
src 和 dest 必须非 null:传 null 直接抛
NullPointerException,尤其注意集合转数组后未判空就拷贝 - srcPos ≥ 0 且 srcPos + length ≤ src.length:越界检查在 native 层执行,失败即抛异常
- destPos ≥ 0 且 destPos + length ≤ dest.length:目标数组容量不足时不会自动扩容,而是直接报错
-
length ≥ 0:传负数立刻抛
IllegalArgumentException
常见错误场景与对应防御写法
以下典型误用在实际代码中高频出现,应固化为检查习惯:
-
源数组长度判断缺失:如
arraycopy(arr, 5, buf, 0, 10)未确认arr.length >= 15→ 建议提前断言:if (arr.length - srcPos -
目标数组复用导致覆盖:同一数组既作 src 又作 dest(如扩容逻辑),若
srcPos 且区间重叠,会因复制顺序导致中间数据被覆盖 → 应改用 <code>Arrays.copyOfRange或手动循环避开重叠 -
类型不匹配却强转绕过编译检查:如把
Object[]强转为String[]再拷贝,运行时报ArrayStoreException→ 拷贝前用src.getClass().getComponentType()与dest.getClass().getComponentType()校验兼容性
替代方案选型要匹配场景本质
并非所有拷贝都该用 arraycopy,盲目追求性能反而引入风险:
- 浅拷贝对象数组?
Arrays.copyOf更安全,自动处理类型校验和扩容逻辑 - 需要截取+转换?用
Stream.of(arr).skip(n).limit(m).toArray()语义清晰,避免索引计算错误 - 跨类型拷贝(如 int[] → long[])?
arraycopy不支持,必须显式循环或使用ByteBuffer等工具类 - 仅需部分元素且数量小?直接 for 循环可读性更高,JIT 优化后性能差异可忽略
单元测试必须覆盖边界与异常路径
仅测“正常流程”等于没测。建议每个 arraycopy 调用配套以下断言:
- 正向用例:srcPos=0、length=src.length、destPos=0,验证全量拷贝结果一致
- 边界用例:srcPos = src.length-1、length=1;destPos = dest.length-1 → 确保末尾对齐无越界
- 异常用例:用
assertThrows验证当length > src.length - srcPos时确实抛出ArrayIndexOutOfBoundsException - 重叠用例:src==dest 且 srcPos=1、destPos=0、length=3 → 检查是否产生预期覆盖行为(或按设计拒绝执行)
不复杂但容易忽略。真正稳定的 arraycopy 用法,是把参数关系变成可验证的逻辑断言,而不是靠经验硬记。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











