ArrayList源码分析
源码分析
private int size; //ArrayList中元素的个数
transient Object[] elementData; //用该数组来存储ArrayList中的元素
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//默认的ArrayList中元素的最大个数
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//新建ArrayList的时候若没有指定ArrayList的初始大小,则默认是一个空的数组,直到往ArrayList中添加了元素则不为空
private static final int DEFAULT_CAPACITY = 10; //新建ArrayList对象的时候,若没有指定List的容量,则默认为10
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
rangeCheckForAdd(index);//检查插入的index是否合法,index的位置范围为[0, size]
modCount++;
final int s;
Object[] elementData;//新建一个临时数组
//elementData = this.elementData将原来的数组赋值给现在新建立的数组
//(elementData = this.elementData).length,求出elementData的长度
//size:List中包含的元素个数,而不是值List的容量大小。
//如果List中的元素的个数等于其实际容量的大小,说明该进行扩容了,不然无法容纳新插入的元素
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();//grow方法用于扩大elementData[]的容量大小
//src:源数组,srcPos:源数组拷贝的起点位置,dest:目地数组,destPos:目的数组接受拷贝值的起点位置,length:拷贝的长度
//arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
//从elementData的index位置拷贝s - index个元素到elementData的index + 1的位置
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
//插入元素element到index这个位置
elementData[index] = element;
//更新size的大小
size = s + 1;
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//扩大elementData[]的容量大小
private Object[] grow() {
//让elementData[]的容量增加。注意,这里写的虽然是size + 1,新的数组的容量可能不止加1。实际上是新建了一个数组,再将原来的数组中的元素拷贝到新的元素中。
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
//Arrays.copyOf(T[] original, int newLength)
//将原来的数组original拷贝到一个新的数组,并使得新数组的长度为newLength
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
/**
* Returns a capacity at least as large as the given minimum capacity.
* Returns the current capacity increased by 50% if that suffices.
* Will not return a capacity greater than MAX_ARRAY_SIZE unless
* the given minimum capacity is greater than MAX_ARRAY_SIZE.
*
* @param minCapacity the desired minimum capacity
* @throws OutOfMemoryError if minCapacity is less than zero
*/
//该方法用来在扩容时指明应该扩容到多大
//返回List的应该扩容到多大。
//返回的容量大小至少应该和给定的最小容量一样大。如果内存空间足够的话,会使得容量相比原来的扩容50%
//除非调用这个程序时指定要扩容的容量 > MAX_ARRAY_SIZE(默认的最大容量),否则不会返回一个大于MAX_ARRAY_SIZE的数
//minCapacity用来指明扩容后的容量最小应该是多大,但是实际扩容后的容量大小并不一定等于minCapacity,得分情况讨论
private int newCapacity(int minCapacity) {
// overflow-conscious code
//扩容前elementData的容量,ArrayList中的元素实际上还是存储在数组中的
int oldCapacity = elementData.length;
//新的容量 = 以前的容量 + 以前的容量 / 2 ; 相当于就是把容量扩大了一半,新的容量是原来的容量的1.5倍
//默认情况下应该是扩容1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);//oldCapacity >> 1相当于是oldCapacity / 2
//为什么会出现newCapacity - minCapacity <= 0的情况
//扩容的目的是让List的容量变大,出现newCapacity - minCapacity <= 0的原因有:
//1.如果List原来是一个空的List,其容量为0,根据这个空的List计算而得到的newCapacity自然也是0,那么指定的minCapacity很大可能会大于newCapacity
//2.如果指定的minCapacity < 0,那么可能是因为Java的虚拟机的容量不够了,无法再分配容量给该数组了,也就是说无法为List扩容了。
// 所以设置为一个小于0的数,用来抛出一个OOM异常。什么时候可能会抛出OOM异常呢?见解释: Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.
//3.排除前面两种情况,说明指定的minCapacity要大于程序默认扩容的容量(newCapacity),那这种情况,就以指定的minCapacity作为List扩容后的容量大小.
if (newCapacity - minCapacity <= 0) {
//elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA说明该List是一个空的List,一个空的List一旦被放入了元素,若未指定初始容量的大小,则会自动为其扩容到默认的初始容量DEFAULT_CAPACITY(10)
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
//如果minCapacity < 0,则会抛出OutOfMemoryError异常
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
//程序能走到这里,则说明用户指定的minCapacity < 程序默认扩容的容量(newCapacity),那么就以newCapacity作为List扩容后的容量大小
//如果扩容后的容量newCapacity大于MAX_ARRAY_SIZE(List的最大容量),则返回一个最大容量,若newCapacity不大于MAX_ARRAY_SIZE,则直接返回当前newCapatity
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}