ArryList源码分析

  ArrayList 是 Java 中非常常用的一个集合类,它实现了 List 接口,并且底层是基于 动态数组(也叫 可变大小数组)来存储数据的。它提供了对元素的快速随机访问,并且可以动态地增加容量。

1. 基本结构

ArrayList 类位于 java.util 包中,继承了 AbstractList 并实现了 List 接口。ArrayList 底层维护了一个数组,通过这个数组来存储集合中的元素。其最重要的成员变量是 elementData,它是一个对象数组,存储了 ArrayList 中的元素。

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    private static final long serialVersionUID = 8683452581122892189L;

    // 该数组存储集合中的元素
    transient Object[] elementData;
    
    // 当前元素的个数
    private int size;

    // 默认的初始容量
    private static final int DEFAULT_CAPACITY = 10;

    // 空数组
    private static final Object[] EMPTY_ARRAY = {};

    public ArrayList() {
        this.elementData = EMPTY_ARRAY;
    }
    }
}


2. 构造函数

ArrayList 提供了多个构造函数:

  • 默认构造函数:当没有传递初始容量时,ArrayList 会初始化一个容量为 10 的默认数组。
  • 带有初始容量的构造函数:可以指定一个初始容量,
  • 非负容量:这个构造函数确保了用户不会传入负数作为容量,因为负数容量没有意义,抛出异常可以避免不正确的初始化。
  • 容量为 0:当容量为 0 时,直接使用一个空数组 EMPTY_ELEMENTDATA,而不是分配一个新的对象数组。这可以节省内存开销。实际上,ArrayList 是通过动态扩容来增加容量的,起始容量 0 不会影响后续的正常使用。
  • 初始容量大于 0:允许用户根据需求初始化一个足够容量的 ArrayList,避免多次扩容,提高性能。

public ArrayList(int initialCapacity) {
    // 如果初始容量大于 0
    if (initialCapacity > 0) {
        // 为 `elementData` 数组分配指定容量的内存空间
        this.elementData = new Object[initialCapacity];
    } 
    // 如果初始容量等于 0
    else if (initialCapacity == 0) {
        // 设置 `elementData` 为一个空的静态常量数组
        this.elementData = EMPTY_ELEMENTDATA;
    } 
    // 如果初始容量小于 0,抛出异常
    else {
        throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
    }
}


3.添加元素

1. private void add(E e, Object[] elementData, int s)

这个方法是一个私有的辅助方法,主要用来向 ArrayList 添加元素。它接收以下参数:

  • e:要添加的元素。
  • elementData:当前存储元素的数组。
  • s:当前 ArrayList 中的元素数量。

功能:

  • 如果当前数组 elementData 已满(即 s == elementData.length),则通过调用 grow() 方法扩容数组。
  • 然后将元素 e 添加到数组的 s 位置。
  • 更新 size,表示当前 ArrayList 的大小,size = s + 1

这段代码表示了向数组末尾添加元素时的基本操作,如果数组已经满了,会进行扩容。

private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)
        elementData = grow();
    elementData[s] = e;
    size = s + 1;
}

2. public boolean add(E e)

这个方法是 ArrayList 类的公共 add 方法,用于将元素添加到列表的末尾。它的实现很简单,调用了上面提到的私有 add 方法来执行实际的添加操作。

  • modCount++modCount 是 ArrayList 用来跟踪结构修改次数的变量。修改次数会在每次改变 ArrayList 内容时增加,这主要是为了支持 Iterator 的快速失败机制(fail-fast)。如果在迭代过程中修改了集合,Iterator 会抛出 ConcurrentModificationException
  • add(e, elementData, size):通过调用私有的 add 方法来将元素 e 添加到 elementData 数组中的 size 位置。

最终,add 方法返回 true,表示元素已成功添加。

public boolean add(E e) {
    modCount++;
    add(e, elementData, size);
    return true;
}

3. public void add(int index, E element)

这个方法是 ArrayList 的另一个 add 方法,用于在指定的位置 index 插入元素。它比单纯的添加元素复杂,因为插入元素时可能会影响到现有元素的位置。此方法的实现步骤如下:

  • rangeCheckForAdd(index):检查插入位置是否有效。rangeCheckForAdd 方法会验证 index 是否在有效范围内(0 到 size)。如果超出范围,会抛出 IndexOutOfBoundsException 异常。
  • modCount++:修改次数增加。
  • 计算当前 size 和 elementData 数组:
    • 如果数组已经满了(即 s == elementData.length),则扩容数组。
  • System.arraycopy():这是数组元素的移动操作。System.arraycopy 方法会将 index 位置及之后的元素向后移动一位,为新元素腾出空间。
    • elementData, index, elementData, index + 1, s - index 表示将数组中从 index 开始的元素移动到右边一个位置(从 index + 1 开始)。
  • elementData[index] = element;:将新元素 element 放入指定的 index 位置。
  • 更新 size = s + 1:最后更新 size,表示当前元素数量增加。

4.扩容

这段代码来自于 ArrayList 的 grow 方法,用于在 ArrayList 容量不足时扩展其底层数组的容量。

private Object[] grow(int minCapacity) {
    return elementData = Arrays.copyOf(elementData,
                                       newCapacity(minCapacity));
}

这段代码是 ArrayList 类中的一个方法,用于计算扩容时的新数组容量。它的目的是根据当前数组的容量和所需的最小容量(minCapacity),计算一个合适的新容量,并确保容量不会过大,避免出现内存溢出问题。

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;  // 获取当前数组的容量
    int newCapacity = oldCapacity + (oldCapacity >> 1);  // 计算新的容量,增加50%
    
    // 如果新的容量小于所需的最小容量,则做进一步的处理
    if (newCapacity - minCapacity <= 0) {
        // 如果当前数组是空数组并且其容量是默认空数组容量
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            return Math.max(DEFAULT_CAPACITY, minCapacity);  // 返回最大值,确保容量不小于默认值
        
        // 如果 minCapacity 小于 0,说明发生了溢出,抛出内存不足异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        
        // 否则,返回 minCapacity 确保新容量至少为所需的容量
        return minCapacity;
    }

    // 如果新的容量小于等于最大数组大小,则直接返回新的容量
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);  // 否则调用 hugeCapacity 方法,确保容量不超过最大限制
}
 

定义时只初始化,添加第一个元素时,创建为10,超出时扩容为1.5倍。

5.数组与集合之间的转换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值