ArrayList 的底层确实是用数组实现的 ,并且它的 add() 方法的核心逻辑就依赖于这个内部数组。下面我们从源码角度(以 Java 8+ 为主)来详细解析:
1. ArrayList 底层结构
scala
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable {
// 存储元素的底层数组(JDK 8+ 是 Object[],早期版本可能为 transient)
transient Object[] elementData;
// 实际元素个数
private int size;
}
elementData就是ArrayList内部用来存数据的动态数组。- 初始容量默认为 10(如果你用无参构造函数)。
2. add(E e) 方法的核心流程
arduino
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保容量足够
elementData[size++] = e; // 添加元素并增加 size
return true;
}
关键在 ensureCapacityInternal() ------ 它负责扩容检查。
3. 扩容机制(核心!)
步骤分解:
(1) ensureCapacityInternal(minCapacity)
ini
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 如果是默认空数组,则至少扩容到 DEFAULT_CAPACITY = 10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
(2) ensureExplicitCapacity(minCapacity)
scss
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 用于 fail-fast 机制
if (minCapacity - elementData.length > 0)
grow(minCapacity); // 需要扩容!
}
(3) grow(int minCapacity) ------ 真正的扩容逻辑
ini
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 新容量 = 旧容量 + 旧容量 >> 1 (即 1.5 倍)
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果 1.5 倍还不够(比如批量添加大量元素),就用 minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 处理超大数组(接近 Integer.MAX_VALUE)
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 创建新数组,并复制旧数据(调用 Arrays.copyOf)
elementData = Arrays.copyOf(elementData, newCapacity);
}
4. 关键点总结
| 特性 | 说明 |
|---|---|
| 底层结构 | Object[] elementData 数组 |
| 初始容量 | 无参构造时为 0 (延迟初始化),第一次 add 时扩到 10 |
| 扩容策略 | 1.5 倍增长 (old + old >> 1) |
| 扩容操作 | 调用 Arrays.copyOf() 创建新数组并复制元素(时间复杂度 O(n) ) |
| 线程安全 | ❌ ArrayList 不是线程安全的 |
举例:
当前容量 10,添加第 11 个元素 → 扩容到 10 + 5 = 15
再添加到第 16 个 → 扩容到 15 + 7 = 22(因为 15 >> 1 = 7)
对比:ArrayList vs 普通数组
| 特性 | 普通数组 | ArrayList |
|---|---|---|
| 大小固定? | ✅ 是 | ❌ 动态扩容 |
| 泛型支持? | ❌ | ✅ |
| 提供丰富方法? | ❌ | ✅(add/remove/contains等) |
| 内存开销 | 小 | 稍大(对象头 + size 字段等) |
📌 总结
ArrayList底层是Object[]数组。add()方法会检查容量,不够就扩容。- 扩容规则:1.5 倍(右移一位加原值) 。
- 扩容本质是创建新数组 + 复制旧数据(
Arrays.copyOf) ,所以频繁扩容会影响性能 → 建议预估容量并用new ArrayList<>(initialCapacity)初始化。