Java数组拷贝最高效方式是System.arraycopy,需严格按src、srcPos、dest、destPos、length顺序传参,并校验边界以避免ArrayStoreException等异常。

Java 中数组拷贝最高效的方式就是 System.arraycopy,它由 JVM 底层直接支持,比手动循环或 Arrays.copyOf 更快、更轻量。但参数稍有不慎就会抛出 ArrayStoreException、IndexOutOfBoundsException 或静默拷贝错误——关键在于五个参数的语义和边界对齐。
核心参数含义与顺序不能错
System.arraycopy(src, srcPos, dest, destPos, length) 五个参数必须严格按此顺序理解:
-
src:源数组(不能为空,否则抛
NullPointerException) -
srcPos:从源数组哪个索引开始读(≥ 0,且 ≤
src.length) -
dest:目标数组(不能为空,类型需兼容,否则抛
ArrayStoreException) -
destPos:往目标数组哪个索引开始写(≥ 0,且 ≤
dest.length) - length:要拷贝多少个元素(≥ 0;若为 0,不报错也不拷贝;若过大,会越界)
常见误用:把 length 当成“拷贝到第几个位置”,实际它是“拷贝元素个数”。例如想拷贝前 5 个元素,应写 length = 5,不是 5 - 1。
安全校验边界:避免运行时异常
虽然 arraycopy 内部会检查边界,但提前验证能让问题暴露得更早、更明确:
立即学习“Java免费学习笔记(深入)”;
- 确保
srcPos + length ≤ src.length - 确保
destPos + length ≤ dest.length - 若涉及子类数组拷贝(如
Object[]拷贝String[]),需确认dest类型能容纳src元素(否则运行时报ArrayStoreException)
示例:安全封装一个带校验的拷贝方法
// 不推荐裸调用 system.arraycopy// 推荐先校验再调用
if (src == null || dest == null) throw new IllegalArgumentException();
if (srcPos if (srcPos + length > src.length || destPos + length > dest.length) {
throw new IndexOutOfBoundsException("Copy range exceeds array bounds");
}
System.arraycopy(src, srcPos, dest, destPos, length);
典型高效场景与写法
掌握几种高频用法,避免绕路:
-
扩容并复制:创建新数组后整数组拷贝
int[] newArr = new int[oldArr.length * 2];<br>System.arraycopy(oldArr, 0, newArr, 0, oldArr.length);
-
截取子数组(类似 Arrays.copyOfRange):
int[] sub = new int[end - start];<br>System.arraycopy(src, start, sub, 0, sub.length);
-
向后移动元素(如 ArrayList add(0, x) 的底层):
// 在索引 2 处插入,需将 [2..len-1] 整体后移一位<br>System.arraycopy(arr, 2, arr, 3, arr.length - 3);
-
数组合并(两段拼接):
System.arraycopy(a, 0, combined, 0, a.length);<br>System.arraycopy(b, 0, combined, a.length, b.length);
注意类型兼容性与泛型擦除限制
System.arraycopy 是原生方法,不进行泛型检查,但要求运行时类型兼容:
-
String[] → Object[]✅(子类→父类) -
Object[] → String[]❌(运行时报ArrayStoreException) -
List<String>[] → List<?>[]✅(擦除后都是List[]) - 基本类型数组之间互转(如
int[] → long[])不支持,必须手动遍历转换
泛型集合转数组时,不要用 new Object[size] 然后强转,而应使用带类型信息的数组(如 new String[size]),否则 arraycopy 后可能在后续赋值时报错。


















