在 ArrayList 的 add() 方法中,真正决定是否扩容的逻辑始于 ensureCapacityInternal(int minCapacity)。这个方法是扩容机制的入口点,负责处理初始容量设定和最小容量校准。
一、方法作用解析
private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
minCapacity:表示当前需要的最小容量(通常是size + 1)。DEFAULTCAPACITY_EMPTY_ELEMENTDATA:无参构造时elementData的初始值(一个共享的空数组)。DEFAULT_CAPACITY:常量,值为 10。
✅ 关键逻辑:
如果是首次添加元素(即使用无参构造创建的
ArrayList),则将minCapacity至少设为 10。例如:第一次
add()时minCapacity = 1,但会被提升为10。
这解释了为什么 new ArrayList<>() 在第一次添加元素后,内部数组容量是 10,而不是 1。
二、为什么这样设计?
- 避免频繁小容量扩容
若首次只分配 1 个位置,第二次就要扩容到 2,第三次到 3……效率极低。
直接初始化为 10,可满足大多数轻量级场景,减少早期扩容次数。 - 区分“显式指定容量”与“默认构造”
new ArrayList<>(5):elementData不等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,不会强制设为 10;new ArrayList<>():走默认逻辑,首次扩容至少 10。
三、后续流程:ensureExplicitCapacity
ensureCapacityInternal 最终调用 ensureExplicitCapacity(minCapacity),该方法会:
- 检查
minCapacity是否超过当前elementData.length; - 若超过,则触发真正的扩容(调用
grow()方法,执行 1.5 倍扩容 + 数组拷贝)。
总结
ensureCapacityInternal 是 ArrayList 扩容机制中的智能预判层:
- 对默认构造的列表,首次扩容直接拉到 10,避免“一步一扩”;
- 为后续的容量判断和实际扩容(
grow)提供准确的minCapacity输入。
理解这一过程,有助于我们:
- 合理预设初始容量(如已知要存 1000 条数据,就
new ArrayList<>(1000)); - 避免因频繁扩容导致的性能抖动;
- 更深入掌握 Java 集合类的设计哲学:在灵活性与效率之间取得平衡。