system.arraycopy()仅高效复制数据而不扩容,真正扩容需三步:计算新容量、创建新数组、用arraycopy搬运元素;它比for循环快因cpu指令优化、单次边界检查和jit向量化。

System.arraycopy() 本身不扩容,它只做高效复制;真正扩容必须先创建更大数组,再用它把旧数据搬过去。理解这点是避免误用的关键——它不是“扩容方法”,而是“扩容中最快搬运工”。
扩容的三步固定动作
无论数组类型或长度,扩容逻辑都逃不开这三个环节:
- 计算新容量(比如原长 × 1.5,向上取整)
- 用 new int[newLength] 或 new String[newLength] 创建新数组
- 调用 System.arraycopy(src, 0, dest, 0, src.length) 把全部有效元素从头到头搬过去
为什么 arraycopy 比 for 循环快得多
它快不是因为“语法糖”,而是 JVM 在底层做了三件事:
- 直接调用 CPU 的内存块复制指令(如 x86 的 REP MOVS),一次搬几十甚至上百字节,不是逐个赋值
- 只在开始做一次边界和类型检查,复制过程中跳过所有索引校验(而 for 循环每次都要判断 i
- JIT 编译器对它做了深度内联和向量化优化,小数组走精简路径,大数组自动切分并行搬运
常见错误与避坑提醒
看似简单,但实际写错会导致空指针、越界或静默丢数据:
- 忘记更新引用:newArr 创建了,但没写 arr = newArr,后续操作还在旧数组上
- length 传错:复制长度写成 newArr.length 而不是 src.length,会导致末尾多出默认值(如 0 或 null)覆盖逻辑
- 目标数组类型不匹配:把 Object[] 往 Integer[] 里 copy,运行时报 ArrayStoreException,编译期不报错
- 混淆 Arrays.copyOf:它内部也调 arraycopy,但多了 new 数组的开销;高频扩容场景建议手写三步,更可控
一个可直接复用的整型扩容模板
适用于需要精确控制扩容策略的工具类或底层容器:
int[] expand(int[] src, float factor) {
if (src == null) return new int[1];
int newLength = Math.max(src.length + 1, (int) (src.length * factor));
int[] dest = new int[newLength];
System.arraycopy(src, 0, dest, 0, src.length);
return dest;
}
调用示例:arr = expand(arr, 1.5f); ——简洁、无副作用、语义清晰。











