arraylist的add(e e)先调用ensurecapacityinternal(size+1)检查并确保容量,再执行elementdata[size++]=e写入元素;首次添加时底层数组为空,扩容至10;后续按1.5倍增长,超限时触发arrays.copyof复制,时间复杂度均摊o(1),扩容时退化为o(n)。

分析 ArrayList 的 add(E e) 方法执行流程,关键在于理解它如何联动扩容机制完成“自动增长”。整个过程不是简单赋值,而是先检查、再扩容(如有必要)、最后写入,环环相扣。
add 方法入口:先保容量,再存元素
每次调用 add(E e),核心逻辑只有两步:
- 调用
ensureCapacityInternal(size + 1)—— 判断当前数组是否能容纳“加一个之后”的总元素数; - 执行
elementData[size++] = e—— 真正把元素放进数组,并使size自增 1。
注意:size 是实际元素个数,elementData.length 才是底层数组的容量。两者不等时,就可能出现“有空间但没数据”或“满容量需扩容”的情况。
ensureCapacityInternal:决定首次扩容的关键跳转
该方法负责计算“真正需要的最小容量”,重点处理无参构造后的首次添加:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 如果底层数组是
DEFAULTCAPACITY_EMPTY_ELEMENTDATA(即用new ArrayList()创建的空列表),则取Math.max(10, size + 1),首次必为 10; - 否则直接使用传入的
minCapacity(即size + 1); - 接着把计算结果交给
ensureExplicitCapacity做最终判断。
ensureExplicitCapacity 与 grow:触发扩容的临界点
这里才是扩容与否的“判决点”:
- 比较
minCapacity - elementData.length > 0; - 若成立(即所需容量超出现有数组长度),就调用
grow(minCapacity); - 若不成立,说明空间足够,流程直接结束,跳过扩容。
例如:第 1 次 add → size=0,需容量 1 → 数组长度为 0 → 触发 grow → 扩到 10;
第 11 次 add → size=10,需容量 11 → 当前数组长度为 10 → 再次触发 grow。
grow 方法:1.5 倍扩容的实际执行者
grow 负责申请新数组并复制数据:
- 新容量默认为旧容量右移一位再相加(
oldCapacity + (oldCapacity >> 1)),等价于 ×1.5; - 若计算结果仍小于
minCapacity(比如首次扩容时旧容量为 0),则直接取minCapacity; - 还会检查是否超过
MAX_ARRAY_SIZE(Integer.MAX_VALUE - 8),防止溢出; - 最后用
Arrays.copyOf完成旧数组到新数组的拷贝。
这个复制过程是 add 最耗时的部分,时间复杂度从均摊 O(1) 退化为 O(n)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










