ArrayList源码解析

ArrayList源码解析

简介:

ArrayList 是 java 集合框架中比较常用的数据结构了。继承自 AbstractList,实现了 List 接口。底层基于数组实现容量大小动态变化。允许 null 的存在。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。

1、成员属性介绍

ArrayList 底层是基于数组来实现容量大小动态变化的。

// 默认初始容量
private static final int DEFAULT_CAPACITY = 10;
// 用于空实例的共享空数组实例。
private static final Object[] EMPTY_ELEMENTDATA = {};
// 用于默认大小的空实例的共享空数组实例。 我们将其与 EMPTY_ELEMENTDATA 区分开来,以了解添加第一个元素时要膨胀多少。简单来讲就是第一次添加元素时知道该 elementData 从空的构造函数还是有参构造函数被初始化的。以便确认如何扩容。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// ArrayList 的元素存储在其中的数组缓冲区。 ArrayList 的容量就是这个数组缓冲区的长度。 添加第一个元素时,任何带有 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都将扩展为 DEFAULT_CAPACITY。
transient Object[] elementData;
// ArrayList 的大小(它包含的元素数)。size 是指 elementData 中实际有多少个元素,而 elementData.length 为集合容量,表示最多可以容纳多少个元素。
private int size;
// 要分配的数组的最大大小。 
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 这个变量是定义在 AbstractList 中的。记录对 List 操作的次数。主要使用是在 Iterator,是防止在迭代的过程中集合被修改。
protected transient int modCount = 0;

2、构造函数

// 构造一个初始容量为 10 的空列表,
// 注意:注释是说构造一个容量大小为 10 的空的 list 集合,但构造函数了只是给 elementData 赋值了一个空的数组,其实是在第一次添加元素时容量扩大至 10 的。
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 构造一个具有指定初始容量的空列表。
// 也就是说:当使用无参构造函数时是把 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 赋值给 elementData。 当 initialCapacity 为零时则是把 EMPTY_ELEMENTDATA 赋值给 elementData。 当 initialCapacity 大于零时初始化一个大小为 initialCapacity 的 object 数组并赋值给 elementData。
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}
// 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表
// 也就是说:使用指定 Collection 来构造 ArrayList 的构造函数
public ArrayList(Collection<? extends E> c) {
    Object[] a = c.toArray();
    if ((size = a.length) != 0) {
        if (c.getClass() == ArrayList.class) {
            elementData = a;
        } else {
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        // replace with empty array.
        elementData = EMPTY_ELEMENTDATA;
    }
}

3、add()方法

add(E e)新增元素
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 索引位赋值
    elementData[size++] = e;
    return true;
}
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    // 此条件成立说明是第一次添加
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        // 返回默认的初始容量大小
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    // list 发生改变的次数
    modCount++;

    // overflow-conscious code
    // 如果元素个数大于数组长度则进行扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
// 扩容的实现
private void grow(int minCapacity) {
    // overflow-conscious code
    // oldCapacity 为 当前数组的长度
    int oldCapacity = elementData.length;
    // newCapacity 为 当前数组的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 此条件成立说明是第一次添加元素,初始容量为10
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 此条件成立说明数组中的元素超出最大限制,这个在部分虚拟机容易内存溢出
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    // 旧的数组赋值到需要扩容大小的数组当中
    elementData = Arrays.copyOf(elementData, newCapacity);
}
add(E e,int index) 在指定位置插入元素
// 在此列表中的指定位置插入指定元素。 将当前在该位置的元素(如果有)和任何后续元素向右移动(向它们的索引添加一个)。
public void add(int index, E element) {
    // 检查 index是否大于0或者index是否小于 size 否则抛出数组越界异常
    rangeCheckForAdd(index);
	// 确保是否需要进行扩容 (上面已讲)
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 索引位以后的元素进行向后位移
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    // //在索引位插入元素
    elementData[index] = element;
    size++;
}

4、remove()方法

// 移除此列表中指定位置的元素。 将任何后续元素向左移动(从它们的索引中减去一个)
public E remove(int index) {
    // 此处的索引只能是 当前数组容量 -1 否则抛出 数组越界异常
    rangeCheck(index);

    modCount++;
    // 获取当前数组需要移除元素的值
    E oldValue = elementData(index);
	// index 索引位后面的元素个数
    int numMoved = size - index - 1;
   	// 此条件成立说明,当前索引位后面的元素都需要向左移动一位
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 清除size-1索引位的元素,并进行-1
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

5、get()方法

// 返回当前数组中指定索引位的元素
public E get(int index) {
    // 检查 index 是否是 小于 数组越界异常(此方法不会检查负数)
    rangeCheck(index);
	// 获得当前索引位的元素
    return elementData(index);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值