ArrayList扩容机制:添加前检查容量,若size+Δ>elementData.length则触发;首次add扩容至10,后续按1.5倍(oldCapacity + oldCapacity>>1)增长,不足则取所需最小值;通过Arrays.copyOf新建数组并拷贝实现。

准确描述 ArrayList 的扩容机制,关键在于讲清“何时扩、怎么算、如何做”三个层次,不笼统说“自动增长”,也不误传“满才扩”或“固定加10”。
扩容触发时机:添加前检查,非填满才扩
每次调用 add(E) 或 addAll 时,都会先执行 ensureCapacityInternal(size + 1)(单个元素)或 ensureCapacityInternal(size + numNew)(批量)。判断依据是:当前元素个数 + 待增数量是否超过底层数组长度(即 size + Δ > elementData.length)。不是等数组真被占满才动,而是“放不下就提前扩”。
- 无参构造后首次 add:
elementData是空数组(DEFAULTCAPACITY_EMPTY_ELEMENTDATA),此时直接按Math.max(10, 1)设为 10 - 第 10 个元素加入后,
size == 10,但容量仍是 10,尚未触发扩容 - 第 11 个元素加入前,
size + 1 == 11 > 10,立即触发扩容
新容量计算:1.5 倍为主,按需兜底
扩容核心逻辑在 grow() 方法中,公式为:int newCapacity = oldCapacity + (oldCapacity >> 1);
右移一位等价于除以 2(向下取整),本质是乘以 1.5 并向下取整。
- 10 → 15(10 + 5)
- 15 → 22(15 + 7)
- 22 → 33(22 + 11)
- 但若所需最小容量(如批量添加 100 个,当前容量仅 50)大于该值,则直接取
minCapacity,跳过中间步骤
扩容实际执行:新建数组 + 批量复制
扩容不是修改原数组,而是创建更大数组并迁移数据:
- 调用
Arrays.copyOf(elementData, newCapacity),底层通过System.arraycopy实现高效拷贝 - 拷贝完成后,
elementData引用指向新数组,旧数组等待 GC - 该操作时间复杂度为 O(n),是扩容的主要性能开销
内存与初始化细节:懒加载 + 空数组区分
JDK 8+ 采用懒加载策略,避免无用分配:
-
new ArrayList<>()→elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA(长度为 0 的共享空数组) -
new ArrayList(0)→ 使用EMPTY_ELEMENTDATA,后续扩容按需起步,不强制到 10 - 这种区分确保了“无参构造首次 add 扩到 10”和“指定 0 容量首次 add 扩到 1”逻辑互不干扰

















