详解Java ArrayList

ArrayList 作为 Java 集合框架中最基础且常用的动态数组实现,其内部通过对数组的精细化管理,实现了动态扩容、高效元素操作等核心能力。本文将从源码层面深入拆解 ArrayList 的扩容策略、索引查询、拷贝机制、哈希计算、元素删除、批量操作等关键模块,揭示其设计逻辑与性能优化细节。

  • 动态扩容:通过 1.5 倍增长系数平衡内存与效率;
  • 高效数组操作 :依赖System.arraycopy实现元素移动与拷贝,利用 native 方法提升性能;
  • 浅拷贝策略:在数据隔离与内存复用间取得平衡;
  • fail-fast 机制 :通过modCount检测并发修改,保证数据一致性。

动态扩容

ArrayList 的扩容是其区别于普通数组的核心特性,grow(int minCapacity)方法根据数组初始化状态,采用差异化的扩容逻辑,平衡内存占用与操作效率。

ArrayList 通过grow(int minCapacity)方法实现动态扩容,根据数组初始化状态采取差异化策略:

java 复制代码
private Object[] grow(int minCapacity) {
    int oldCapacity = elementData.length;
    if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        int newCapacity = ArraysSupport.newLength(oldCapacity,
                minCapacity - oldCapacity, /* 最小增长量 */
                oldCapacity >> 1           /* 首选增长量(原容量的1/2) */);
        return elementData = Arrays.copyOf(elementData, newCapacity);
    } else {
        return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
    }
}
  • 指定初始容量场景 :按原容量的 1.5 倍扩容(oldCapacity >> 1等价于除以 2),兼顾内存利用率与扩容效率;
  • 默认空数组场景 :首次扩容直接使用DEFAULT_CAPACITY(默认 10)或所需最小容量的较大值,避免频繁扩容。

索引查询

ArrayList 通过分层设计的查询方法,实现从 "存在性检查" 到 "精准索引定位" 的全场景支持,核心依赖遍历与 null 值兼容逻辑。

ArrayList 提供多层次索引查询方法,兼顾通用性与效率:

存在性检查

java 复制代码
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

首次 / 末次索引查询

java 复制代码
public int indexOf(Object o) {
    return indexOfRange(o, 0, size);
}

public int lastIndexOf(Object o) {
    return lastIndexOfRange(o, 0, size);
}

范围查询

java 复制代码
int indexOfRange(Object o, int start, int end) {
    Object[] es = elementData;
    if (o == null) {
        for (int i = start; i < end; i++) {
            if (es[i] == null) return i;
        }
    } else {
        for (int i = start; i < end; i++) {
            if (o.equals(es[i])) return i;
        }
    }
    return -1;
}
  • null 值处理:单独判断避免空指针异常;
  • 遍历策略:正序 / 逆序遍历分别适配首次 / 末次查询需求;
  • 性能特性:时间复杂度 O (n),适用于中小规模数据查询。

拷贝

ArrayList 的拷贝操作通过**clone()toArray()**实现,均采用浅拷贝策略:

java 复制代码
public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size); // 数组结构拷贝
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        throw new InternalError(e);
    }
}

拷贝特性

  • 物理分离 :新 ArrayList 的elementData是独立数组,修改新数组结构(如 add/remove)不会影响原数组;
  • 逻辑共享 :数组元素为对象引用时,新旧数组指向同一对象实例,修改元素属性(如user.setName("new"))会双向影响;
  • 应用场景:适合快速复制数组结构,无需深拷贝元素的场景(如临时数据处理)。

哈希计算

ArrayList 的哈希计算遵循 Java 集合框架标准,通过累加策略保证顺序敏感性:

java 复制代码
int hashCodeRange(int from, int to) {
    final Object[] es = elementData;
    int hashCode = 1;
    for (int i = from; i < to; i++) {
        Object e = es[i];
        hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
    }
    return hashCode;
}

优势

  • 31 的选择
    • 31 是奇素数,素数特性减少哈希冲突(若用合数,哈希值会被因子整除,分布更集中);
    • 31 可通过移位优化计算:31 * i = (i << 5) - i(左移 5 位等价于乘以 32,减 i 即乘以 31),提升效率。
  • 顺序敏感性 :累加方式使元素顺序影响最终哈希值(如[a,b][b,a]哈希值不同),符合 List "有序集合" 的特性;
  • null 兼容:null 元素哈希值记为 0,避免空指针异常。

元素删除

ArrayList 的删除操作通过fastRemove()shiftTailOverGap()实现,核心依赖System.arraycopy优化性能:

单个元素删除

java 复制代码
private void fastRemove(Object[] es, int i) {
    modCount++;
    final int newSize;
    if ((newSize = size - 1) > i)
        System.arraycopy(es, i + 1, es, i, newSize - i);
    es[size = newSize] = null; // 置null便于GC回收
}

范围元素删除

java 复制代码
private void shiftTailOverGap(Object[] es, int lo, int hi) {
    System.arraycopy(es, hi, es, lo, size - hi);
    for (int to = size, i = (size -= hi - lo); i < to; i++)
        es[i] = null;
}

性能优化点

  • 批量移动 :通过System.arraycopynative 方法实现高效内存块复制;
  • 空间回收:删除后置 null 操作帮助 JVM 进行垃圾回收;
  • 时间复杂度:单次删除为 O (n),批量删除通过遍历优化减少移动次数。

批量操作

ArrayList 通过**batchRemove()统一实现removeAll()retainAll()**:

java 复制代码
boolean batchRemove(Collection<?> c, boolean complement,
                    final int from, final int end) {
    Objects.requireNonNull(c);
    final Object[] es = elementData;
    int r;
    // 定位首个需要保留/删除的元素
    for (r = from;; r++) {
        if (r == end) return false;
        if (c.contains(es[r]) != complement) break;
    }
    int w = r++;
    try {
        for (Object e; r < end; r++)
            if (c.contains(e = es[r]) == complement)
                es[w++] = e; // 原地覆盖保留元素
    } catch (Throwable ex) {
        System.arraycopy(es, r, es, w, end - r);
        w += end - r;
        throw ex;
    } finally {
        modCount += end - w;
        shiftTailOverGap(es, w, end); // 清理尾部无效元素
    }
    return true;
}
  • 原地操作:通过覆盖写入减少数组复制开销;
  • 异常安全:catch 块保证异常时数据完整性;
  • 通用设计 :通过complement参数切换删除 / 保留逻辑,复用代码逻辑。
  • complement 参数
    • false(removeAll):保留c.contains(es[r]) == false的元素(删除交集);
    • true(retainAll):保留c.contains(es[r]) == true的元素(保留交集)。
  • 原地覆盖 :通过写指针w在原数组上覆盖元素,避免创建新数组,节省内存;
  • 异常安全:catch 块保证遍历过程中出现异常时,未处理元素仍能正确复制,避免数据丢失。

批量添加

ArrayList 支持尾部追加与指定位置插入两种批量添加方式:

尾部追加

java 复制代码
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    modCount++;
    int numNew = a.length;
    if (numNew == 0) return false;
    Object[] elementData;
    final int s;
    if (numNew > (elementData = this.elementData).length - (s = size))
        elementData = grow(s + numNew);
    System.arraycopy(a, 0, elementData, s, numNew);
    size = s + numNew;
    return true;
}

指定位置插入

java 复制代码
public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);
    // 扩容检查...
    int numMoved = s - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index,
                         elementData, index + numNew, numMoved);
    System.arraycopy(a, 0, elementData, index, numNew);
    size = s + numNew;
    return true;
}
相关推荐
x***B4111 小时前
Rust unsafe代码规范
开发语言·rust·代码规范
第二只羽毛1 小时前
单例模式的初识
java·大数据·数据仓库·单例模式
4***g8941 小时前
Java进阶-SpringCloud设计模式-工厂模式的设计与详解
java·spring cloud·设计模式
__万波__1 小时前
二十三种设计模式(五)--建造者模式
java·设计模式·建造者模式
北郭guo1 小时前
Java设计模式 【理论+代码实现】 让你从小白到大佬的蜕变
java·开发语言·设计模式
计算机徐师兄1 小时前
Java基于微信小程序的贝壳活动助手【附源码、文档说明】
java·微信小程序·贝壳活动助手·贝壳活动助手小程序·贝壳活动助手微信小程序·java贝壳活动助手小程序·java贝壳活动助手微信小程序
Gavin在路上1 小时前
架构设计之COLA架构
java·数据库·架构
MediaTea1 小时前
Python 库手册:gc 垃圾回收
java·开发语言·jvm·python·算法
碎像1 小时前
阿里云 ARMS 应用实时监控服务
java·阿里云·云计算