public class ArrayListextends AbstractList implements List , RandomAccess, Cloneable, java.io.Serializable
ArrayList类继承自抽象类AbstractList,实现了List接口,随机存取RandomAccess接口,克隆接口Cloneable,序列化接口Serializable。
通常,我们使用Arraylist添加一个对象往往无需过多考虑,直接add()即可,无需担心其容量是否超过限制,其原因就在于Arraylist源码中,实现add()方法之前会查看其容量是否够用,不够则会自动‘扩容’然后再执行add()添加元素,即自动扩容。
让我们从一个空的数组列表添加元素开始,看一下源码是如何实现的。
List list = new ArrayList();list.add("A");
首先,List list = new ArrayList();初始化了一个空数组列表list,具体是ArrayList类源码中:
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}
/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA * will be expanded to DEFAULT_CAPACITY when the first element is added. */ transient Object[] elementData; // non-private to simplify nested class access /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size;
初始化ArrayList对象的同时创建了一个默认为空的Object数组变量elementData。然后list.add("A")对应的是源码中的add()方法:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
如图中所示,public boolean add(E e){}方法会执行modCount++;然后调用add(e,elementData,size)方法,最后返回布尔类型的ture。
modCount在ArrayList中定义如下:
private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
doc说明:
/**
* The number of times this list has been <i>structurally modified</i>.* Structural modifications are those that change the size of the* list, or otherwise perturb it in such a fashion that iterations in* progress may yield incorrect results....很多结构化地改变数组的操作都会用到modCount计数,用来标识数组被修改的次数。譬如add , set , remove等。
由于是初次添加元素,故modCount++后变为1,来到下一步add(e, elementData, size),此时e为要添加的元素:“A”,elementData为刚刚创建的Object[], size为数组初始容量,值为0(在ArrayList中定义:private int size,int型初始未赋值则为0)
重点看下add方法的具体实现:
private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
由于初始elementData.length==size==0故执行grow()方法,返回值赋给elementData。
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); }
grow有两个重载的方法,无参的grow()会调用有参的grow,参数为size+1。
private Object[] grow(int minCapacity) { return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity)); }
此处size+1=1作为minCapacity,表示最小容量,实际也很好理解,因为add一个对象首先我需要的最小容量是原长度+1,有了最小容量才能进行下一步地添加元素操作,所以通过grow()来确保我arraylist对象的长度,即【扩容】
扩容的操作通过Arrays.copyOf方法实现:
public staticT[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); }
此方法直接将原数组elementData复制到一个新的给定长度的数组中,并返回此新数组对象。
那么新数组长度是多少呢?这个就是newCapacity()中定义的,让我们看一下:
public staticT[] copyOf(U[] original, int newLength, Class newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
http://1.int oldCapacity = elementData.length
此处由于elementData是空数组,所以oldCapacity==elementData.length==0
2.newCapacity = oldCapacity + (oldCapacity >> 1)
这一步是扩容的核心操作,即扩容后新数组的长度=原数组的容量+原数组的容量/2.
通过oldCapacity >> 1(Java移位运算,右移1位相当于除以2)来实现扩容原数组容量的一半
,即ArrayList的扩容是根据原容量的1.5倍来扩容的。
但是此时oldCapacity值为0故newCapacity也为0,扩容无效...
3.if(newCapacity - minCapacity <=0)
经过第二步后的newCapacity=0,小于minCapacity=1故进入下面的步骤:
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
4.return Math.max(DEFAULT_CAPACITY, minCapacity);
DEFAULT_CAPACITY为ArrayList中初始的默认容量,大小为10。定义如下:
return Math.max(DEFAULT_CAPACITY, minCapacity)返回10和minCapacity中的最大值,此处直接返回10
现在,经过newCapacity()计算后的新数组容量为10,让我们回到grow()中的:
Arrays.copyOf将elementData复制到一个容量为10的新Object[]中去,并返回此数组对象elementData,完成了前面一大堆准备工作,并执行扩容后,终于来到了add()方法中的最后两步:
elementData[s] = e;
完成新增元素添加
size = s + 1;
将该ArrayList对象的数量+1