system.arraycopy本身不防indexoutofboundsexception,需调用前手动校验:srcpos≥0且srcpos+length≤src.length、destpos≥0且destpos+length≤dest.length、length≥0;推荐封装带校验的工具方法以兼顾安全与性能。

用 System.arraycopy 防范 IndexOutOfBoundsException,核心不是靠它自己“防”,而是你必须在调用前主动校验所有边界——它不检查、不提示、不兜底,参数一错就直接抛异常。
必须手动验证的三个关键条件
调用前需同时满足以下三项,缺一不可:
- srcPos ≥ 0 且 srcPos + length ≤ src.length:确保源数组起始位置合法,且拷贝长度不超出源数组尾部
- destPos ≥ 0 且 destPos + length ≤ dest.length:目标数组同理,尤其注意它必须已存在且容量足够
- length ≥ 0:复制个数不能为负;若为 0,虽不报错但无实际拷贝动作
推荐的安全封装写法
避免每次调用都重复写一堆 if 判断,可封装一个带校验的工具方法:
public static
if (src == null || dest == null) throw new NullPointerException();
if (srcPos if (srcPos + length > src.length || destPos + length > dest.length) {
throw new IndexOutOfBoundsException("copy would exceed array bounds");
}
System.arraycopy(src, srcPos, dest, destPos, length);
}
这样既保留了 System.arraycopy 的性能优势,又把边界检查收口到一处,调用时更安心。
常见踩坑点与对应做法
这些地方最容易漏掉校验,导致运行时报错:
-
动态计算索引时未重算边界:比如
srcPos = i * 2,要同步检查i * 2 + length ≤ src.length,不能只验i -
复用旧数组但忘了更新 length:源数组被截断或重建后,仍用原来的
length值调用,必须重新确认可用长度 -
混淆 length 含义:
length是“拷贝元素个数”,不是“拷贝到哪个索引”,别和destPos + length混为一谈 -
忽略 null 引用风险:
src或dest为null会直接抛NullPointerException,这虽不是IndexOutOfBoundsException,但常被误判为越界问题
什么时候该换 Arrays.copyOf
如果你需要的是“按需新建数组并拷贝”,而不是往已有数组里填数据,就别硬用 System.arraycopy:
-
Arrays.copyOf(src, newLength)自动处理扩容、新建、拷贝三步,内部已做完整校验 - 当目标容量不确定、或仅需浅拷贝整个数组时,它比手写
System.arraycopy更安全简洁 - 性能差异在中小数组上几乎可忽略;只有高频、大块、复用缓冲区场景才值得坚持用
System.arraycopy










