ArrayList集合的底层原理

在 Java 中,ArrayList 是一个常用的动态数组实现类,它位于 java.util 包下。下面详细讲解其底层原理:

1. 基本结构

  • 基于数组实现ArrayList 的底层是一个动态扩容的对象数组transient Object[] elementData),这意味着它可以像普通数组一样通过索引快速访问元素。
  • 继承关系:继承自 AbstractList 并实现了 List 接口,因此支持 List 的所有操作。

2. 初始化与容量

  • 默认容量:当使用无参构造函数 new ArrayList() 时,初始容量为 0(JDK 8 及以后),首次添加元素时扩容为 10
  • 指定容量:使用 new ArrayList(int initialCapacity) 可以指定初始容量,避免频繁扩容。
  • 空参构造的延迟初始化
// 无参构造:初始化为空数组
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 首次添加元素时,容量扩展为 DEFAULT_CAPACITY(10)

3. 动态扩容机制

当元素数量超过数组容量时,ArrayList 会自动扩容:

  1. 计算新容量:默认扩容为原容量的 1.5 倍oldCapacity + (oldCapacity >> 1))。
  2. 创建新数组:使用 Arrays.copyOf() 方法将原数组元素复制到新数组。
  3. 替换引用:将内部数组引用指向新数组。
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity; // 特殊情况:初始容量为0时
    elementData = Arrays.copyOf(elementData, newCapacity);
}

4. 元素操作

  • 添加元素(add(E e)
    • 尾部添加:平均时间复杂度为 O(1),可能触发扩容(概率低)。
    • 指定位置插入add(int index, E element)):需要移动后续元素,时间复杂度为 O(n)
  • 删除元素(remove(int index)
    • 需要移动后续元素,时间复杂度为 O(n)
  • 获取元素(get(int index)
    • 直接通过数组索引访问,时间复杂度为 O(1)
  • 修改元素(set(int index, E element)
    • 直接通过索引替换值,时间复杂度为 O(1)

5. 自动装箱与拆箱

  • 当存储基本数据类型(如 intdouble)时,ArrayList 会自动进行装箱(IntegerDouble)和拆箱操作,可能影响性能。

6. 线程安全性

  • 非线程安全ArrayList 不支持并发访问,多线程环境下可能出现数据不一致问题。
  • 替代方案
    • 使用 Vector(线程安全,但性能较低)。
    • 使用 Collections.synchronizedList(new ArrayList<>())
    • 使用 CopyOnWriteArrayList(写时复制,适合读多写少场景)。

7. 迭代器与 fail-fast 机制

  • 迭代器(Iterator:通过 iterator() 方法获取,支持元素遍历和删除。
  • fail-fast 机制
    • 当迭代过程中检测到数组结构被修改(如添加、删除元素),会抛出 ConcurrentModificationException
    • 通过内部维护的 modCount 变量实现,每次结构修改时递增。

8. 序列化与 transient 关键字

  • elementData 被声明为 transient,表示不自动参与序列化。
  • 原因:数组可能存在未使用的空位,序列化会浪费空间。
  • 自定义序列化逻辑:通过 writeObject() 和 readObject() 方法只序列化实际存储的元素。

9. 优缺点总结

  • 优点
    • 随机访问效率高(O (1))。
    • 支持动态扩容。
  • 缺点
    • 插入和删除操作效率低(O (n))。
    • 扩容会导致数组复制,性能损耗。

10. 适用场景

  • 频繁随机访问元素。
  • 很少进行插入和删除操作。
  • 存储元素数量不确定,但变化不大。

总结

ArrayList 通过动态数组和扩容机制实现了可变长度的列表,适合随机访问场景。理解其底层原理有助于合理使用该类,并在性能敏感的场景下做出优化选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值