Java ArrayList 扩容机制
一、ArrayList 简介
ArrayList
是 Java 集合框架中基于数组实现的可变长度列表,其核心特性是:
- 支持随机访问(通过索引)
- 支持动态扩容
- 插入/删除效率较低(非尾部操作)
二、底层数据结构
// JDK 11+
transient Object[] elementData; // 实际存储元素的数组
三、容量与初始状态
默认构造函数
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
默认初始值为一个空数组,不分配空间,首次添加元素时分配容量。
指定初始容量
public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];}
}
开发中建议:尽量提前估算容量,减少扩容次数
四、扩容机制核心原理
触发条件:
当新增元素导致 size > elementData.length
时触发扩容。
扩容策略:
新容量 = 原容量 + (原容量 >> 1) = 原容量 * 1.5
例如:
- 当前容量 10 → 扩容后为 15
- 当前容量 15 → 扩容后为 22
五、源码详解(以 JDK 8 为例)
添加元素核心方法:
public boolean add(E e) {ensureCapacityInternal(size + 1); // 确保有容量elementData[size++] = e;return true;
}
ensureCapacityInternal(int minCapacity)
private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity(int minCapacity)
private void ensureExplicitCapacity(int minCapacity) {modCount++; // fail-fast 标识if (minCapacity - elementData.length > 0)grow(minCapacity); // 核心:扩容方法
}
grow(int minCapacity)
private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容1.5倍if (newCapacity - minCapacity < 0)newCapacity = minCapacity; // 不够就按最小需求扩if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity); // 复制数组
}
六、最大容量限制
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
超过该限制会抛出 OutOfMemoryError
。
七、扩容操作的成本
- 使用
Arrays.copyOf()
进行数组复制,时间复杂度为O(n)
- 多次扩容会引起频繁复制,影响性能
八、如何避免频繁扩容?
方式一:指定初始容量
List<String> list = new ArrayList<>(1000); // 预估大小
方式二:批量添加前调用 ensureCapacity
list.ensureCapacity(10000); // 批量操作前手动扩容
九、总结对比:不同初始化方式
构造方式 | 初始容量 | 首次添加触发扩容 | 是否推荐 |
---|---|---|---|
new ArrayList() | 0 | 是(容量为10) | ⚠️ 慎用 |
new ArrayList(20) | 20 | 否 | ✅ 推荐 |
new ArrayList(list) | 原容量 | 否 | ✅ 推荐 |
十、扩容流程图
graph TD
A[add(e)] --> B[ensureCapacityInternal]
B --> C[ensureExplicitCapacity]
C --> D{容量够吗?}
D -- 是 --> E[添加成功]
D -- 否 --> F[grow 扩容]
F --> G[复制新数组]
G --> E
十一、常见面试题
Q1:ArrayList 每次扩容增长多少?
- 默认是 1.5 倍(即
old + old/2
)
Q2:频繁 add 元素时怎么优化?
- 预估大小,构造时指定初始容量
- 或调用
ensureCapacity
Q3:ArrayList 最大能容纳多少元素?
Integer.MAX_VALUE - 8
≈ 2^31 - 9
十二、总结
点位 | 描述 |
---|---|
数据结构 | 动态数组 Object[] |
扩容触发 | 新增元素导致数组容量不够 |
扩容增长率 | 1.5倍 |
拷贝机制 | Arrays.copyOf() 整体复制 |
最大容量 | Integer.MAX_VALUE - 8 |
性能建议 | 尽量设定初始容量,避免频繁扩容 |