Java ArrayList底层源码解析:如何用数组实现动态扩容与缩容
·
Java ArrayList底层源码解析:动态扩容与缩容机制
1. 底层数据结构
ArrayList底层通过Object[] elementData数组存储元素,初始容量默认为10(JDK8)。关键字段:
private static final int DEFAULT_CAPACITY = 10;
private transient Object[] elementData;
private int size; // 实际元素数量
2. 动态扩容机制
当添加元素超出当前容量时触发扩容(如add()方法):
- 扩容公式:新容量 = 旧容量 + 旧容量/2
即:$newCapacity = oldCapacity + \left\lfloor \frac{oldCapacity}{2} \right\rfloor$ - 源码逻辑(简化自
grow()方法):
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 右移1位等价于除以2
if (newCapacity < minCapacity) {
newCapacity = minCapacity; // 处理首次扩容等特殊情况
}
elementData = Arrays.copyOf(elementData, newCapacity); // 复制到新数组
}
示例:
初始容量10 → 添加第11个元素时:
$newCapacity = 10 + \left\lfloor \frac{10}{2} \right\rfloor = 15$
3. 缩容机制
ArrayList不会自动缩容,但提供手动缩容方法:
trimToSize()方法:将容量调整为当前元素数量
public void trimToSize() {
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size); // 复制到更小数组
}
}
应用场景:
当elementData远大于size时(如删除大量元素后),调用此方法可释放内存。
4. 关键特性总结
| 机制 | 触发条件 | 核心操作 | 时间复杂度 |
|---|---|---|---|
| 扩容 | 添加元素时size >= capacity |
创建1.5倍新数组并复制数据 | $O(n)$ |
| 缩容 | 手动调用trimToSize() |
创建等于size的新数组并复制 |
$O(n)$ |
5. 设计意图
- 空间换时间:1.5倍扩容平衡了内存占用与减少复制次数的需求
- 避免频繁缩容:手动缩容设计防止在删除-添加交替操作时反复复制数组
最佳实践:
若提前预知数据量,应通过ArrayList(int initialCapacity)指定初始容量,避免多次扩容开销。
更多推荐
所有评论(0)