JDK 8 ArrayList 源码详解(完整版带详细注释)

JDK 8 ArrayList 源码详解(完整版带详细注释)

1. 基本结构和常量定义

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    
    // 序列化版本号
    private static final long serialVersionUID = 8683452581122892189L;
    
    // 默认初始容量
    private static final int DEFAULT_CAPACITY = 10;
    
    // 空数组实例,用于指定容量为0时的构造函数
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
    // 默认容量的空数组实例,用于无参构造函数
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
    // 存储元素的数组,transient关键字表示不参与序列化
    transient Object[] elementData;
    
    // ArrayList中实际存储的元素个数
    private int size;
    
    // 数组能分配的最大容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}

2. 构造函数

/**
 * 无参构造函数
 * 构造一个初始容量为10的空列表
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * 指定初始容量的构造函数
 * @param initialCapacity 初始容量
 * @throws IllegalArgumentException 如果初始容量为负数
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        // 创建指定容量的数组
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        // 容量为0时使用共享的空数组
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        // 负数抛出异常
        throw new IllegalArgumentException("Illegal Capacity: " +
                                           initialCapacity);
    }
}

/**
 * 从集合构造ArrayList
 * @param c 要构造ArrayList的集合
 * @throws NullPointerException 如果集合为null
 */
public ArrayList(Collection<? extends E> c) {
    // 将集合转换为数组
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // 如果数组类型不是Object[],需要进行类型转换
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // 空集合使用共享的空数组
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

3. 核心方法实现

3.1 ensureCapacityInternal方法(内部容量保证)

/**
 * 确保ArrayList内部容量足够
 * @param minCapacity 所需的最小容量
 */
private void ensureCapacityInternal(int minCapacity) {
    // 如果是默认空数组,取默认容量和所需容量的最大值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

/**
 * 明确的容量保证
 * @param minCapacity 所需的最小容量
 */
private void ensureExplicitCapacity(int minCapacity) {
    modCount++; // 修改次数增加,用于快速失败机制
    
    // 如果所需容量大于当前数组长度,需要扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

3.2 grow方法(扩容)

/**
 * 扩容核心方法
 * @param minCapacity 所需的最小容量
 */
private void grow(int minCapacity) {
    // 获取当前数组长度
    int oldCapacity = elementData.length;
    // 新容量为旧容量的1.5倍(位运算优化:oldCapacity + oldCapacity/2)
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    
    // 如果新容量仍小于所需容量,使用所需容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    
    // 如果新容量超过最大数组大小
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    
    // 创建新数组并将原数组元素复制到新数组
    elementData = Arrays.copyOf(elementData, newCapacity);
}

/**
 * 处理超大容量的情况
 * @param minCapacity 所需的最小容量
 * @return 适合的容量
 */
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 溢出
        throw new OutOfMemoryError();
    // 如果所需容量大于最大数组大小,返回Integer.MAX_VALUE,否则返回最大数组大小
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

3.3 add方法

/**
 * 在列表末尾添加元素
 * @param e 要添加的元素
 * @return true(为了符合Collection接口规范)
 */
public boolean add(E e) {
    // 确保容量足够
    ensureCapacityInternal(size + 1);
    // 在末尾添加元素
    elementData[size++] = e;
    return true;
}

/**
 * 在指定位置插入元素
 * @param index 插入位置的索引
 * @param element 要插入的元素
 * @throws IndexOutOfBoundsException 如果索引越界
 */
public void add(int index, E element) {
    // 检查索引范围
    rangeCheckForAdd(index);
    
    // 确保容量足够
    ensureCapacityInternal(size + 1);
    
    // 将index位置及其后的元素向后移动一位
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    // 在指定位置插入元素
    elementData[index] = element;
    size++; // 元素数量增加
}

/**
 * 添加集合中的所有元素到列表末尾
 * @param c 要添加的集合
 * @return 如果列表被修改返回true
 */
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    // 确保容量足够容纳新元素
    ensureCapacityInternal(size + numNew);
    // 将新元素复制到数组末尾
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

/**
 * 在指定位置添加集合中的所有元素
 * @param index 插入位置的索引
 * @param c 要添加的集合
 * @return 如果列表被修改返回true
 */
public boolean addAll(int index, Collection<? extends E> c) {
    // 检查索引范围
    rangeCheckForAdd(index);
    
    Object[] a = c.toArray();
    int numNew = a.length;
    
    // 确保容量足够
    ensureCapacityInternal(size + numNew);
    
    // 计算需要移动的元素个数
    int numMoved = size - index;
    if (numMoved > 0)
        // 将index位置后的元素向后移动numNew位
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);
    
    // 将新元素复制到指定位置
    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

3.4 get方法

/**
 * 获取指定位置的元素
 * @param index 元素的索引
 * @return 指定位置的元素
 * @throws IndexOutOfBoundsException 如果索引越界
 */
public E get(int index) {
    // 检查索引范围
    rangeCheck(index);
    // 返回指定位置的元素
    return elementData(index);
}

/**
 * 索引范围检查(不包含size)
 * @param index 要检查的索引
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/**
 * 索引范围检查(包含size,用于添加元素时)
 * @param index 要检查的索引
 */
private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

/**
 * 构造越界异常信息
 * @param index 越界的索引
 * @return 异常信息字符串
 */
private String outOfBoundsMsg(int index) {
    return "Index: "+index+", Size: "+size;
}

/**
 * 获取指定位置的元素(类型转换)
 * @param index 元素索引
 * @return 指定位置的元素
 */
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}

3.5 set方法

/**
 * 替换指定位置的元素
 * @param index 要替换元素的索引
 * @param element 新元素
 * @return 被替换的旧元素
 * @throws IndexOutOfBoundsException 如果索引越界
 */
public E set(int index, E element) {
    // 检查索引范围
    rangeCheck(index);
    
    // 获取旧元素
    E oldValue = elementData(index);
    // 设置新元素
    elementData[index] = element;
    return oldValue;
}

3.6 remove方法

/**
 * 移除指定位置的元素
 * @param index 要移除元素的索引
 * @return 被移除的元素
 * @throws IndexOutOfBoundsException 如果索引越界
 */
public E remove(int index) {
    // 检查索引范围
    rangeCheck(index);
    
    modCount++; // 修改次数增加
    
    // 获取要移除的元素
    E oldValue = elementData(index);
    
    // 计算需要移动的元素个数
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // 将index+1位置后的元素向前移动一位
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 将最后一个位置置为null,帮助GC
    elementData[--size] = null;
    
    return oldValue;
}

/**
 * 移除指定元素的第一个匹配项
 * @param o 要移除的元素
 * @return 如果成功移除返回true
 */
public boolean remove(Object o) {
    if (o == null) {
        // 处理null元素
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        // 处理非null元素
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

/**
 * 快速移除方法(不进行边界检查,不返回被移除的元素)
 * @param index 要移除元素的索引
 */
private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // help GC
}

3.7 clear方法

/**
 * 移除所有元素
 */
public void clear() {
    modCount++;
    
    // 将所有元素置为null,帮助GC
    for (int i = 0; i < size; i++)
        elementData[i] = null;
    
    size = 0; // 元素数量置为0
}

3.8 contains方法

/**
 * 判断列表是否包含指定元素
 * @param o 要查找的元素
 * @return 如果包含返回true
 */
public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

/**
 * 返回指定元素第一次出现的索引
 * @param o 要查找的元素
 * @return 元素第一次出现的索引,如果不存在返回-1
 */
public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

/**
 * 返回指定元素最后一次出现的索引
 * @param o 要查找的元素
 * @return 元素最后一次出现的索引,如果不存在返回-1
 */
public int lastIndexOf(Object o) {
    if (o == null) {
        for (int i = size-1; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = size-1; i >= 0; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

4. 迭代器实现

/**
 * 返回迭代器
 */
public Iterator<E> iterator() {
    return new Itr();
}

/**
 * ArrayList的迭代器实现
 */
private class Itr implements Iterator<E> {
    int cursor;       // 下一个要返回的元素的索引
    int lastRet = -1; // 上次返回的元素的索引,-1表示没有
    int expectedModCount = modCount; // 期望的修改次数

    public boolean hasNext() {
        return cursor != size;
    }

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification(); // 检查并发修改
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * 检查并发修改
     */
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

5. 其他重要方法

5.1 size和isEmpty方法

/**
 * 返回列表中元素的数量
 */
public int size() {
    return size;
}

/**
 * 判断列表是否为空
 */
public boolean isEmpty() {
    return size == 0;
}

5.2 toArray方法

/**
 * 返回包含所有元素的数组
 */
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

/**
 * 返回包含所有元素的指定类型数组
 */
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // 如果数组长度小于列表大小,创建新的数组
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    // 将元素复制到指定数组
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

5.3 trimToSize方法

/**
 * 将此ArrayList实例的容量调整为列表的当前大小
 * 应用程序可以使用此操作来最小化ArrayList实例的存储空间
 */
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

6. 序列化相关方法

/**
 * 序列化写入方法
 */
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // 写入默认的序列化信息
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // 写入数组大小
    s.writeInt(size);

    // 依次写入每个元素
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

/**
 * 序列化读取方法
 */
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;

    // 读取默认的序列化信息
    s.defaultReadObject();

    // 读取数组大小
    s.readInt();

    if (size > 0) {
        // 确保容量
        ensureCapacityInternal(size);

        Object[] a = elementData;
        // 依次读取每个元素
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

7. 总结

7.1 ArrayList的特点

  1. 底层实现:基于动态数组实现
  2. 随机访问:支持O(1)时间复杂度的随机访问
  3. 动态扩容:当容量不足时自动扩容(1.5倍)
  4. 有序性:保持元素的插入顺序
  5. 允许重复:可以存储重复元素
  6. 允许null:可以存储null元素
  7. 非线程安全:不是线程安全的

7.2 时间复杂度分析

  • 访问元素:O(1) - 通过索引直接访问
  • 搜索元素:O(n) - 需要遍历数组
  • 插入元素
    • 末尾插入:O(1) 平摊时间复杂度
    • 中间插入:O(n) - 需要移动后续元素
  • 删除元素:O(n) - 需要移动后续元素
  • 扩容操作:O(n) - 需要复制所有元素

7.3 空间复杂度

  • 存储空间:O(n) - n为存储的元素个数
  • 额外空间:可能有O(n)的额外空间(扩容时的数组)

7.4 使用建议

  1. 适用场景

    • 需要频繁随机访问元素
    • 在列表末尾频繁添加/删除元素
    • 元素数量相对稳定
  2. 不适用场景

    • 在列表开头或中间频繁插入/删除元素(考虑使用LinkedList)
    • 多线程环境(考虑使用Vector或Collections.synchronizedList())
  3. 性能优化

    • 如果能预估元素数量,使用带初始容量的构造函数
    • 对于大量数据,可以使用trimToSize()方法释放多余空间

ArrayList是Java集合框架中最常用的集合类之一,其设计简洁高效,适用于大多数需要动态数组的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值