arraylist扩容通过容量判断→新容量计算→数组复制三步完成:add()触发ensurecapacityinternal检查,grow()按1.5倍(oldcapacity + oldcapacity>>1)计算新容量,不足则取mincapacity,超限走hugecapacity,最终由arrays.copyof调用system.arraycopy完成浅拷贝。

直接看 JDK 8 源码就能理清 ArrayList 扩容的完整链路:它不是凭空变大,而是靠 容量判断 → 新容量计算 → 数组复制 三步闭环完成的。关键不在“要不要扩”,而在于“扩多少”和“怎么搬”。
扩容触发点在 add() 方法里
每次调用 add(E e),第一件事就是检查是否够用:
- 执行
ensureCapacityInternal(size + 1),传入“加完这个元素后至少需要几个位置” - 如果当前
elementData.length ,就进入扩容流程 - 无参构造首次添加时,
elementData是DEFAULTCAPACITY_EMPTY_ELEMENTDATA(长度为 0),这时会直接把最小容量设为DEFAULT_CAPACITY(即 10)
新容量按 1.5 倍算,但不是死规则
真正算容量是在 grow(int minCapacity) 方法里:
- 先取旧容量:
int oldCapacity = elementData.length - 再算理论新容量:
int newCapacity = oldCapacity + (oldCapacity >> 1)(位运算等价于 ×1.5,更快) - 但如果批量添加(比如
addAll)导致minCapacity比这个 1.5 倍还大,就直接用minCapacity - 最后还要防溢出:超过
MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8)就走hugeCapacity特殊处理
数组拷贝靠 Arrays.copyOf,本质是 System.arraycopy
Arrays.copyOf(elementData, newCapacity) 是扩容的最终动作:
- 它内部调用的是 native 的
System.arraycopy,效率极高 - 拷贝的是引用值(Object[]),属于浅拷贝 —— 原数组和新数组里的对象地址相同,只是数组容器变了
- 没被覆盖的旧数组会在下次 GC 时回收,频繁扩容会增加 GC 压力
注意两个空数组的区别
源码里有两个长度为 0 的静态数组,作用不同:
-
DEFAULTCAPACITY_EMPTY_ELEMENTDATA:无参构造(new ArrayList())用,首次 add 触发扩容到 10 -
EMPTY_ELEMENTDATA:显式指定容量为 0(new ArrayList(0))用,首次 add 就按需扩(比如加 1 个就扩成 1)











