首先了解ArrayList集合类常用的构造方法以及常用的成员方法:
常用的构造方法有:
ArrayList<E>(); //默认构造器
ArrayList<E>(Collection <? extends E> c); //将容器C作为构造参数
ArrayList(int initialCapacity); //以初始容量作为构造参数
常用的成员方法有:
//添加元素的方法
boolean add(E e);
boolean addAll(Collection <? extends E> c);
//获取元素的方法
E get(int index);
boolean isEmpty();
int size();
Iterator<E> iterator();
//删除元素方法
E remove(int index);
下面将通过阅读源码对上述方法进行逐个分析:
1. 首先看一下ArrayList类的定义
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
由上述代码可见, ArrayList类实现了List、RandomAccess、Cloneable、Serializable接口,同时扩展了AbstractList类。
ArrayList中定义成员变量如下:
//缺省的初始化容量
private static final int DEFAULT_CAPACITY = 10;
//Shared empty array instance used for empty instances.
//共享的空数组实例,用于新建ArrayList空实例,static final修饰
private static final Object[] EMPTY_ELEMENTDATA = {};
//共享的空数组实例,用于新建默认大小的空ArrayList实例。采用static final修饰。
//区别与上面的EMPTY_ELEMENTDATA是为了当插入第一个元素时用该扩展为默认容量DEFAULT_CAPACITY。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//数组用于缓冲保存在ArrayList中的元素。
//数组的长度就是ArrayList的容量。
transient Object[] elementData;
//ArrayList所包含元素的个数
private int size;
//elementData数组所能分配的最大数组长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2. 分析ArrayList构造方法
2.1 ArrayList()
构造方法
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
将默认空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA复制给elementData.
2.2ArrayList<E>(Collection <? extends E> c)
构造方法
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); //将容器中的元素转变为数组
if ((size = elementData.length) != 0) { //如果容器C中的元素个数不为0
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//如果容器C中元素个数为0,则将elementData赋值为空数组EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
}
}
2.3 ArrayList(int initialCapacity)
构造方法
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) { //如果用户指定的初始化容量大于0
this.elementData = new Object[initialCapacity]; //则将elementData数组新建长度为initialCapacity
} else if (initialCapacity == 0) { 如果用户指定的初始化容量等于0
this.elementData = EMPTY_ELEMENTDATA; //令elementData数组赋值为空数组
} else { //如果用户指定的初始化容量小于0, 则会抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
3. 元素的添加
3.1 add(E e)
方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); 调用了ensureCapacity方法,是否需要进行扩增
elementData[size++] = e; //插入元素到elementData中,并将size加1,记录ArrayList中元素个数
return true; //返回成功
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //如果elementData数组为默认空数组
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); //取默认容量和输入参数中较大者
}
ensureExplicitCapacity(minCapacity); //是否扩增的必要
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //modCount++修改次数自增
if (minCapacity - elementData.length > 0) //如果增加的元素已经超过了elementData数组的长度
grow(minCapacity); //调用grow函数进行扩增
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length; //获取elementData原长度
int newCapacity = oldCapacity + (oldCapacity >> 1); //新容量扩增为原来的1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity; //如果仍然比所需的最小容量minCapacity小,则新长度为minCapacity,主要发生在新建数组数组为空时插入第一个元素
if (newCapacity - MAX_ARRAY_SIZE > 0) //如果新容量大于最大容量
newCapacity = hugeCapacity(minCapacity); //根据原来所需的最小容量进行扩增,而所需容量的最小值通常跟size差不多大
elementData = Arrays.copyOf(elementData, newCapacity); //扩增后复制原数组中元素
}
private static int hugeCapacity(int minCapacity) { //当需要新容量大于最大容量时
if (minCapacity < 0) //如果minCapacity<0,说明长度由最大溢出为负数
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE : //返回Integer的最大
MAX_ARRAY_SIZE; //否则返回数组最大容量限制
}
3.2 addAll(Collection <? extends E> c)
方法
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length; //获取将要添加的容器中元素个数
ensureCapacityInternal(size + numNew); // 查看当前ArrayList元素个数+新增元素个数是否大于elementData数组长度,从而判断是否需要进行扩增
System.arraycopy(a, 0, elementData, size, numNew); //新增元素添加到elementData数组size位置后
size += numNew; //改变ArrayList中元素的总数
return numNew != 0; //如果c为空,返回false
}
4. 元素的获取
4.1 get(int index)
方法
public E get(int index) {
rangeCheck(index); //判断访问位置是否产生越界行为
return elementData(index); //返回数组相应位置的元素
}
private void rangeCheck(int index) {
if (index >= size) //判断元素位置是否大于等于size,如果大于等于,则出现了访问越界,抛出异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
4.2 isEmpty()
方法
public boolean isEmpty() {
return size == 0; //通过判断size==0
}
4.3 size()
方法
public int size() {
return size;
}
4.4 iterator()
方法
public Iterator<E> iterator() {
return new Itr(); //返回ArrayList中的内部类Itr
}
//分析内部类Itr中的主要方法
private class Itr implements Iterator<E> {
int cursor; // 下一个返回元素所在下标
int lastRet = -1; // 上一个返回元素的下标
int expectedModCount = modCount; //记录修改次数
public boolean hasNext() {
return cursor != size; //当前游标没有等于size
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification(); //检查是否其他线程对ArrayList进行了修改
int i = cursor; //赋值为即将返回的元素所在下标
if (i >= size) //大于size则抛出异常
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData; //令局部数组引用指向外部的elementData引用
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1; //令游标指向下一个元素
return (E) elementData[lastRet = i]; //返回i指向的元素,并将i复制给lastSet记录上一个元素的下标。
}
final void checkForComodification() { //检查是否有其他线程同时修改ArrayList
if (modCount != expectedModCount) //如果有其他线程对ArrayList进行了修改,则抛出异常,快速失败
throw new ConcurrentModificationException();
}
5. 元素的删除
5.1 remove(int index)
方法
public E remove(int index) {
rangeCheck(index); //同样需要对index进行越界访问检查
modCount++; //将修改次数加1
E oldValue = elementData(index); //获取index位置处的元素
int numMoved = size - index - 1; //需要将index之后的元素往前移,numMoved保存需要往前移动的元素个数
if (numMoved > 0) //如果需要进行移动的个数大于0
System.arraycopy(elementData, index+1, elementData, index,
numMoved); //复制移动
elementData[--size] = null; //将size减1,前移之后需要同时将原来数组最后一个元素位置size-1置为Null,方便GC回收。
return oldValue;
}