ArrayList扩容时通过Arrays.copyOf间接调用System.arraycopy进行数组拷贝,仅在size等于容量时触发,新容量为原容量1.5倍,且copyOf底层用native方法高效复制引用而非深克隆。

Java 中 ArrayList 的扩容和内部数组拷贝,底层确实依赖 System.arraycopy,但它**不是直接调用**,而是通过一个封装好的私有方法(如 Arrays.copyOf)间接使用。真正关键的是:这个拷贝发生在 add、addAll、ensureCapacity 等触发扩容的场景中,且只在原数组容量不足时才执行。
扩容时的数组拷贝逻辑
ArrayList 内部维护一个 Object[] elementData。当添加元素导致 size == elementData.length 时,会调用 grow() 方法扩容:
- 新容量一般为旧容量的 1.5 倍(
oldCapacity + (oldCapacity >> 1)) - 然后调用
Arrays.copyOf(elementData, newCapacity) - 而
Arrays.copyOf的底层实现正是System.arraycopy
System.arraycopy 在哪被调用?
以 OpenJDK 为例,Arrays.copyOf(Object[], int) 的源码本质是:
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
// 最终调用:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;
}可以看到:System.arraycopy 负责把原数组从索引 0 开始、复制 min(原长, 新长) 个元素到新数组。
立即学习“Java免费学习笔记(深入)”;
管理和控制 macOS 系统功能。包括查看系统信息、管理进程、控制音量/亮度、 网络管理、电源管理、截图、剪贴板、Finder 操作等。当用户要求查看系统状态、 控制系统设置、管理进程、截图、调节音量亮度、查看网络信息、 关机重启睡眠等 Mac 系统操作时使用。
为什么不用 for 循环逐个赋值?
System.arraycopy 是 JVM 内置的本地方法(native),由 C/C++ 实现,在多数平台上有高度优化:
- 连续内存块拷贝可利用 CPU 的 SIMD 指令(如 SSE/AVX)批量处理
- 避免 Java 层循环的边界检查、类型检查开销
- 对对象引用数组,只需复制引用值(8 字节指针),不触发对象本身复制
你也可以手动模拟 ArrayList 的拷贝行为
比如自己实现一个简易扩容逻辑:
Object[] oldArray = {...};
int newSize = oldArray.length * 2;
Object[] newArray = new Object[newSize];
System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); // 关键一行注意参数顺序:System.arraycopy(src, srcPos, dest, destPos, length),顺序错会导致静默失败或数组越界异常。
不复杂但容易忽略:ArrayList 的拷贝只发生在扩容时,日常 get/set 完全不涉及数组拷贝;所有“浅拷贝”语义都源于 System.arraycopy 只复制引用,不深克隆对象本身。

















