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加一,这里的modCount给ArrayList的迭代器使用的,在并发操作被修改时,提供快速失败行为(保证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实例的容量