ArrayList JDK1.8原理分析

一、主要属性

//通过ArrayList实现的接口可知,其支持随机访问,能被克隆,支持序列化
public class ArrayList extends AbstractList
        implements List, RandomAccess, Cloneable, java.io.Serializable
{ 
  //默认初始容量
    private static final int DEFAULT_CAPACITY = 10; 

    //被用于空实例的共享空数组实例
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Object[]类型的数组,保存了添加到ArrayList中的元素。ArrayList的容量是该Object[]类型数组的长度
     * 当第一个元素被添加时,任何空ArrayList中的elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA将会被
     * 扩充到DEFAULT_CAPACITY =10(默认容量)。
     */
    transient Object[] elementData; //非private是为了方便嵌套类的访问

    // ArrayList的大小(指其所含的元素个数)
    private int size;
}
// 构造一个默认初始容量为10的空列表
public ArrayList() {
  this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;  //DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
}

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) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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);
    }

ArrayList构造一个默认初始容量为10的空列表:

  1. 初始情况:elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; size = 0;

  2. 当向数组中添加第一个元素时,通过add(E e)方法中调用的ensureCapacityInternal(size + 1)方法,即ensureCapacityInternal(1);

  3. 在ensureCapacityInternal(int minCapacity)方法中,可得的minCapacity=DEFAULT_CAPACITY=10,然后再调用ensureExplicitCapacity(minCapacity)方法,即ensureExplicitCapacity(10);

  4. 在ensureExplicitCapacity(minCapacity)方法中调用grow(minCapacity)方法,即grow(10),此处为真正具体的数组扩容的算法,在此方法中,通过elementData = Arrays.copyOf(elementData, 10)具体实现了elementData数组初始容量为10的构造。

二、扩容

从add()与addAll()方法中可以看出,每当向数组中添加元素时,都要去检查添加元素后的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求。
在jdk1.8中,向用户提供了一个public的方法ensureCapacity(int minCapacity)使用户可以手动的设置ArrayList实例的容量,以减少递增式扩容的次数。

如果不是自己调用ensureCapacity的话,那么默认每次扩容的大小为原来的1.5倍

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容为原来的1.5倍
        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);
    }

三、Fail-Fast机制

fail-fast 机制java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。
在foreach循环中调用ArryayList新增删除扩容时,比如add、remove、ensureCapacity等方法时,迭代器会抛出ConcurrentModificationException异常,直接禁止并发修改。
ConcurrentModificationException异常原因和解决方法

你可能感兴趣的:(ArrayList JDK1.8原理分析)