arraylist扩容在add()前检查容量,若size+1>当前容量即触发;默认初始容量10,后续按1.5倍扩容(oldcapacity + oldcapacity>>1),不足时直接取所需最小值;扩容通过arrays.copyof复制数据,时间复杂度o(n),预估容量可显著提升性能。

扩容什么时候发生
不是等数组“满了”才扩,而是在添加前就检查容量是否够用。每次调用 add() 或 addAll() 时,都会先计算:当前元素个数 + 待增数量 是否超过底层数组长度(即 size + Δ > elementData.length)。只要放不下,立刻扩容。
例如:容量为10的 ArrayList 已存10个元素,第11次 add() 调用前就会触发扩容——此时 size 还是10,但 size + 1 == 11 > 10,条件成立。
新容量怎么算出来的
核心公式是:newCapacity = oldCapacity + (oldCapacity >> 1),也就是旧容量加它的一半(右移1位等价于整除2),结果向下取整,整体效果≈1.5倍。
- 首次 add:从空数组出发,直接设为
Math.max(10, 所需最小值),所以默认变成10 - 10 → 15(10 + 10>>1 = 10 + 5)
- 15 → 22(15 + 15>>1 = 15 + 7)
- 22 → 33(22 + 22>>1 = 22 + 11)
但如果批量添加大量元素(比如 addAll 100个,而当前容量只有50),计算出的1.5倍值(75)仍不够,那就直接取所需最小值(100),跳过中间计算。
扩容时数据怎么搬过去
扩容本质是换数组 + 搬数据。ArrayList 不修改原数组,而是调用 Arrays.copyOf(elementData, newCapacity) 创建新数组。
这个方法底层依赖 System.arraycopy()——一个 native 方法,高效完成内存块复制。它把原数组从索引0开始、最多复制 min(原长度, 新长度) 个元素到新数组起始位置。
整个过程不涉及元素遍历或对象重构造,只是内存级拷贝,因此速度快,但仍是 O(n) 时间复杂度。
为什么推荐预估容量并调用 ensureCapacity
频繁扩容会反复分配内存、执行 System.arraycopy,带来明显性能开销。比如向空 ArrayList 添加10万个元素,默认策略下会扩容约17次,每次都要复制全部已有元素。
提前调用 list.ensureCapacity(100000),可一次性分配足够空间,避免多次复制:
- 默认初始化添加10万条:耗时约15–25毫秒
- 预设容量后添加10万条:耗时降至约5–10毫秒
尤其在已知数据规模的批量导入、日志聚合、缓存预热等场景,这一步简单却关键。










