ArrayList集合底层原理

1. 底层数据结构

  • 核心是一个 Object[] 数组
    ArrayList 内部维护一个 Object 类型的数组 elementData,用于存储所有元素。

    transient Object[] elementData; // 实际存储元素的数组
  • 默认初始容量

    • 默认初始容量为 10(通过无参构造器创建时)。

    • 可指定初始容量(new ArrayList<>(100)),避免频繁扩容。


2. 动态扩容机制

扩容触发条件

当添加元素(add())时,如果当前数组已满(size == elementData.length),会自动触发扩容。

扩容规则
  1. 计算新容量
    新容量一般为旧容量的 1.5 倍(通过位运算 oldCapacity + (oldCapacity >> 1) 实现)。

    int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5 倍扩容
  2. 处理最小扩容需求
    如果用户一次添加多个元素(如 addAll()),新容量可能需更大,取 需求容量 和 1.5 倍旧容量 的较大值。

  3. 数组拷贝
    通过 Arrays.copyOf() 创建一个新数组,并将旧数组数据复制到新数组中。

    elementData = Arrays.copyOf(elementData, newCapacity);
示例
  • 初始容量为 10,添加第 11 个元素时触发扩容 → 新容量为 15。

  • 继续添加到第 16 个元素 → 再次扩容到 22(15 × 1.5 = 22.5,向下取整为 22)。


3. 基本操作原理

添加元素(add(E e)
  • 直接追加
    时间复杂度 O(1)(不触发扩容时)。

  • 扩容时
    时间复杂度 O(n)(需复制数组),但分摊时间复杂度仍为 O(1)

插入元素(add(int index, E e)
  • 移动元素
    将插入位置后的元素向后移动一位(通过 System.arraycopy())。

    System.arraycopy(elementData, index, elementData, index + 1, size - index);
  • 时间复杂度
    O(n)(最坏情况下需移动所有元素)。

删除元素(remove(int index)
  • 移动元素
    将删除位置后的元素向前移动一位。

    System.arraycopy(elementData, index + 1, elementData, index, size - index - 1);
  • 时间复杂度
    O(n)(最坏情况下需移动所有元素)。

查询元素(get(int index)
  • 直接访问数组

    return (E) elementData[index]; // 时间复杂度 O(1)

4. 关键特性

优点
  1. 动态扩容:无需手动处理数组扩容,适合数据量不确定的场景。

  2. 随机访问高效:通过索引直接访问元素,时间复杂度 O(1)。

  3. 内存紧凑:连续存储,缓存友好,适合遍历操作。

  4. 兼容泛型:支持泛型(如 ArrayList<String>),类型安全。

缺点
  1. 插入/删除效率低:需移动元素,时间复杂度 O(n)。

  2. 内存浪费:扩容机制可能导致未使用的预留空间(如容量为 15,实际只存 11 个元素)。

  3. 非线程安全:多线程环境下需手动同步或改用 Vector(性能更低)。


5. 与普通数组的对比

特性普通数组ArrayList
长度固定初始化后长度不可变动态扩容
类型可以是基本类型(如 int[]只能存储对象(需装箱/拆箱)
内存管理无额外开销有容量预留(可能浪费内存)
功能扩展无内置方法提供丰富 API(如排序、遍历等)

6. 源码设计细节

  • 优化删除操作
    删除元素后,将最后一个位置置为 null(帮助垃圾回收)。

    elementData[--size] = null; // 显式清除引用
  • 快速失败机制(Fail-Fast)
    通过 modCount 记录修改次数,迭代时检测并发修改并抛出 ConcurrentModificationException

  • 序列化优化
    elementData 标记为 transient,序列化时仅写入实际元素(避免序列化空余容量)。


适用场景

  • 高频随机访问:如通过索引快速读取数据。

  • 数据量动态变化:需要自动扩容的场景。

  • 顺序遍历操作:如批量处理数据。


总结

ArrayList 通过动态数组的机制,在普通数组的基础上实现了灵活性和功能扩展:

  • 动态扩容:1.5 倍增长策略平衡了内存和性能。

  • 高效随机访问:底层数组实现 O(1) 的索引访问。

  • 功能丰富:提供增删改查、排序、遍历等 API。

但其插入/删除效率低的缺点,在需要频繁修改数据的场景下,可改用 LinkedList(基于链表)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值