ArrayList的底层实现

ArrsyList底层实现原理

public class ArrayList<E> extends AbstractList<E>

        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

RandomAccess标识其支持快速随机访问;

Cloneable标识其支持对象复制;

Serializable标识其可序列化;

ArrsyList的成员变量:

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

private static final Object[] EMPTY_ELEMENTDATA = {};//ArrayList实例共享的一个空数组

private transient Object[] elementData; //真正存储ArrayList中的元素的数组;

private int size;//存储ArrayList的大小,不是elementData的长度

ArrsyList 的增长机制:

每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量

相关的方法:

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;

}

public static int max(int a, int b) {

        return (a >= b) ? a : b;

}

minCapacity为ArrayList要保证的最小空间大小,首先判断内部数组elementData是否是初始的空数组(当ArrayList是空实例的情况),如果是的话,且minCapacity比DEFAULT_CAPACITY小,则设minCapacity为默认的初始容量大小DEFAULT_CAPACITY

 

 

private void ensureExplicitCapacity(int minCapacity) {

        modCount++;

        if (minCapacity - elementData.length > 0)

            grow(minCapacity);

            

}

 

首先,是对修改次数modCount加一,这里的modCountArrayList的迭代器使用的,在并发操作被修改时,提供快速失败行为(保证modCount在迭代期间不变,否则抛出ConcurrentModificationException异常),接着判断minCapacity是否大于当前ArrayList内部数组长度,大于的话调用grow方法对内部数组elementData扩容

 

private void grow(int minCapacity) {

        int oldCapacity = elementData.length;

        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);

    }

    private static int hugeCapacity(int minCapacity) {

        if (minCapacity < 0)

            throw new OutOfMemoryError();

        return (minCapacity > MAX_ARRAY_SIZE) ?

            Integer.MAX_VALUE :

            MAX_ARRAY_SIZE;

    }

 

首先,获取内部数组elementData长度,并对它的大小增加1.5倍(oldCapacity + (oldCapacity >> 1)),赋给newCapacity,当newCapacity仍然比minCapacity(要保证的最小空间大小)小的时候,直接让newCapacity 等于minCapacity;然后再判断newCapacity 是不是大于MAX_ARRAY_SIZE,如果大于的话,调用hugeCapacity方法,处理大容量空间的情况,该方法判断是否溢出(抛出OutOfMemoryError),以及当minCapacity大于MAX_ARRAY_SIZE时,直接返回Integer.MAX_VALUE;最后就是真正地数组扩容了,调用Arrays.copyOf方法,拷贝旧的内部数组内容到一个新的(长度为newCapacity)的数组,并更改内部数组elementData的引用为新数组

数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素是多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量

 

猜你喜欢

转载自blog.csdn.net/adrian_dai/article/details/79430162