ArrayList是日常开发中使用非常频繁的容器,今天看一下它的源码。ArrayList的源码其实很简单,它就是一个动态数组,我们先从new开始看起:
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
上述是ArrayList的一个无参构造器,我们来分别看一下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
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
根据以上的代码可以看出,DEFAULTCAPACITY_EMPTY_ELEMENTDATA是静态的、final的一个空数组变量。其实new ArrayList();就是创建了一个空的数组。DEFAULTCAPACITY_EMPTY_ELEMENTDATA是静态的、final的一个空数组变量。elementData就是我们实际要操作的那个数组对象。无参构造非常的简单,然后它也有一个有参构造方法:
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
上述的代码,很容易可以看出是指定数组长度的一个有参构造方法,如果指定的大小大于0就创建一个指定长度的对象数组,如果等于零就创建一个空数组,EMPTY_ELEMENTDATA定义如下:
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
否则就抛出非法容量的异常。
还有一个构造方法:
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
上述构造方法就是通过一个集合来创建一个新的数组,很简单,不再过多介绍。然后我们看下ArrayList常用的几个方法的源码。
首先add()方法是最常用的方法之一,源码如下:
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 检查容量是否合法, Increments modCount!!
// 数组扩容后将数据添加到合适的位置 并size+1
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 如果是第一次 true
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果是空数组的话我们就比较输入长度和默认的长度的大小
//private static final int DEFAULT_CAPACITY = 10; 默认长度为10
//使用Math的函数输出大的那个,做为指定的容量
// 第一次为10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 确保明确的容量,扩容
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //记录修改的次数 protected transient int modCount = 0;
//modCount是一个计数器,在多线程操作的情况下来判断这个list是否被别的线程操作过,如果操
//作过会抛出ConcurrentModificationException
// 第一次 10 - 0 > 0
if (minCapacity - elementData.length > 0)//这里判断当前的容量减去原数组的长度如果大于0说明需要扩容了,于是调用 grow(minCapacity)进行扩容操作
// 扩容
grow(minCapacity);
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
* 其实就是再创建一个更大的数组,并将原来的元素复制过去,扩容大小为原来的大小加上原来大小的一半 int newCapacity = oldCapacity + (oldCapacity >> 1);
*/
private void grow(int minCapacity) {
// 记录原来的容量
int oldCapacity = elementData.length;
// 计算新的容量 新容量为 老容量的1.5倍 第一次为0
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 把原来数组中的内容拷贝到一个新建的指定容量为newCapacity的数组中,扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
get方法:获取集合中的元素
public E get(int index) {
// 检查下标是否合法
rangeCheck(index);
// 通过下标从数组中返回对应的元素
return elementData(index);
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
set方法:修改集合中的元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
remove方法:移除指定的元素
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
// 记录要移动的元素的个数
int numMoved = size - index - 1;
if (numMoved > 0)
// 源数组 开始下标 目标数组 开始下标 长度
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
add(index,ele)方法:
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
FailFast机制
快速失败机制,是java集合类应对并发访问在对集合进行迭代过程中,内部对象结构发生变化一种防护措施.这种错误检测的机制为这种有可能发生错误,通过抛出java.util.ConcurrentModificationException
就是检查前面提到的modCount变量
效果:
public class ThreadIterate extends Thread {
private List list;
public ThreadIterate(List list){
this.list = list;
}
@Override
public void run() {
while(true){
for (Iterator iteratorTmp = list.iterator();iteratorTmp.hasNext();) {
iteratorTmp.next();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class ThreadMain {
private static List list = new ArrayList();
public static void main(String[] args) {
new ThreadAdd(list).start();
new ThreadIterate(list).start();
}
}
public class ThreadAdd extends Thread{
private List list;
public ThreadAdd(List list){
this.list = list;
}
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println("loop execute : " + i);
try {
Thread.sleep(5);
list.add(i);
}catch (Exception e){
}
}
}
}
这是就ArrayList的failFast机制,也就是在多线程操作一个List数据的时候如果出现数据安全问题会直接抛异常。
注:FailFast机制图片摘自咕泡P5课程笔记