Arrays.copyOf 是集合扩容时执行拷贝的工具,其高效源于底层调用 JVM 优化的 System.arraycopy,仅复制有效元素、自动填充默认值,语义清晰且安全。

Java 集合源码(如 ArrayList)中,Arrays.copyOf 并不是“在扩容时高效拷贝”的执行者,而是被调用来**完成拷贝动作的工具**——真正决定何时扩容、扩多少、怎么衔接业务逻辑的,是集合类自己封装的扩容策略。它的高效,来自底层对 System.arraycopy 的直接调用和 JVM 层面的优化。
底层调用 System.arraycopy,零拷贝级性能
Arrays.copyOf 所有重载版本最终都归结为同一段核心逻辑:
- 根据
newLength创建新数组(基本类型用new int[newLength],引用类型用Array.newInstance) - 立即调用
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength))
System.arraycopy 是 JVM 内置的本地方法(native),在 HotSpot 中会编译为高度优化的内存块复制指令(如 x86 的 rep movsd),避免 Java 层循环开销,接近硬件级内存拷贝效率。这比手写 for 循环快 3–5 倍,也比反射或 Stream 拷贝稳定得多。
扩容时只复制有效元素,不搬“垃圾”
集合类(如 ArrayList)内部维护 size 字段表示当前实际元素个数,而非数组长度。扩容时传给 copyOf 的是 elementData(底层数组)和目标容量(如 oldCapacity + (oldCapacity >> 1)),但 copyOf 内部只复制前 Math.min(size, newLength) 个位置——也就是说,它天然跳过未使用的数组尾部空间,不会把“空槽”当数据搬。
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
语义清晰 + 自动补默认值,省去边界判断
扩容后的新数组可能比原数组长,多出的位置需初始化为安全默认值(int[] 补 0,Object[] 补 null)。这个填充逻辑由 copyOf 自动完成,无需集合代码额外循环赋值。例如:
-
Arrays.copyOf(new String[]{"a", "b"}, 5)→ 直接返回{"a", "b", null, null, null} - 若用
System.arraycopy,你得先new String[5],再arraycopy,再手动填null——容易漏、易错
与 clone() 和手动 arraycopy 的关键区别
为什么集合源码选 copyOf 而非其他?
-
不用
clone():它返回Object,需强转;且无法扩容(长度固定),对泛型数组还可能触发类型擦除异常 -
不用裸
System.arraycopy:需提前创建目标数组,指定源/目标起始索引和长度,参数多、易传错(比如把length写成size就越界) -
copyOf刚好折中:一行代码表达“我要一个新容器,装下当前所有有效数据,并留点空位”,语义直白,JDK 内部也大量复用(如Arrays.sort的临时缓冲区)
真实源码片段佐证(ArrayList.grow)
以 OpenJDK 25 中 ArrayList 的 grow 方法为例:
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
这里 newCapacity 计算新长度(1.5 倍),copyOf 一步完成:分配 + 复制 + 填充。没有循环、没有判空(除非 elementData 为 null)、不暴露底层偏移量——高效且不易出错。

















