首页 > 代码库 > ArrayList源码阅读

ArrayList源码阅读

ArrayList实现

继承关系
java.lang.Object
    - java.util.AbstractCollection<E>
        - java.util.AbstractList<E>
            - java.util.ArrayList<E>
实现接口

SerializableCloneableIterable<E>, Collection<E>, List<E>, RandomAccess

关键属性
private transient Object[] elementData;    //transient修饰不会序列化,但实现了Serializable接口,重写了readObject和writeObject方法只序列化实际大小
private int size;    //实际大小
常见方法
public boolean add(E e) {
	ensureCapacity(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}
 public void add(int index, E element) {
	if (index > size || index < 0)
	    throw new IndexOutOfBoundsException(
		"Index: "+index+", Size: "+size);
	ensureCapacity(size+1);  // Increments modCount!!
	System.arraycopy(elementData, index, elementData, index + 1,
			 size - index); //elementData[index,size) --> elementData[index+1,size+1)
	elementData[index] = element;
	size++;
 }
ensureCapacity扩容方法:开始前有对modCount修改操作,实现fast-fail迭代
public void ensureCapacity(int minCapacity) {
        modCount++;
        int oldCapacity = elementData.length;
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;
            int newCapacity = (oldCapacity * 3)/2 + 1; //0.5倍扩容策略
                if (newCapacity < minCapacity)
            newCapacity = minCapacity;
                // minCapacity is usually close to size, so this is a win:
                elementData = http://www.mamicode.com/Arrays.copyOf(elementData, newCapacity);>remove方法,移动index+1及其后面元素,并将最后一个元素设置为null,帮助GC回收
 public E remove(int index) {
	RangeCheck(index);
	modCount++;
	E oldValue = http://www.mamicode.com/(E) elementData[index];>
public boolean remove(Object o) {
	if (o == null) {
            for (int index = 0; index < size; index++)
		if (elementData[index] == null) {
		    fastRemove(index);
		    return true;
		}
	} else {
	    for (int index = 0; index < size; index++)
		if (o.equals(elementData[index])) {
		    fastRemove(index);
		    return true;
		}
        }
	return false;
}
fastRemove是私有方法没有返回old value
private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // Let gc do its work
}
重写readObject和writeObject进行序列化和反序列化,保证只会序列化实际大小的数组避免空间浪费,可以看到writeObject的时候有fast fail判断
private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
	// Read in size, and any hidden stuff
	s.defaultReadObject();
        // Read in array length and allocate array
        int arrayLength = s.readInt();
        Object[] a = elementData = http://www.mamicode.com/new Object[arrayLength];>
 private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
	// Write out element count, and any hidden stuff
	int expectedModCount = modCount;
	s.defaultWriteObject();
        // Write out array length
        s.writeInt(elementData.length);
	// Write out all elements in the proper order.
	for (int i=0; i<size; i++)
            s.writeObject(elementData[i]);
	if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
}

迭代器实现

ArrayList支持两种迭代器:IteratorListIterator(双向迭代),实现在AbstractList中
Iterator通过内部类AbstractList$Itr实现
Itr类定义
private class Itr implements Iterator<E>
属性包括
int cursor = 0;   //当前遍历的下标
int lastRet = -1; //最近调用next或previous返回的下标,当调用自身remove方法删除元素后,重置为-1
int expectedModCount = modCount;  //用于检测遍历过程中并发修改
重要方法
hasnext和next方法
public boolean hasNext() {
       return cursor != size();
}
public E next() {
       checkForComodification();
       try {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	 } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	}
}
remove方法
public void remove() {
	    if (lastRet == -1)
		throw new IllegalStateException();
            checkForComodification();
	    try {
		AbstractList.this.remove(lastRet);
		if (lastRet < cursor)
		    cursor--;
		lastRet = -1;
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException e) {
		throw new ConcurrentModificationException();
	    }
}
-next和remove方法前都需要调用checkForComodification检验容器是否被修改,若被修改则抛出ConcurrentModificationException
-调用迭代器自身remove方法不会引起ConcurrentModificationException,这是因为删除元素以后,expectedModCount被重新设置了(expectedModCount = modCount)
-可以看到remove方法执行完一次删除以后,将lastRet设置为-1,下次接着调用就会抛异常。
ListIterator通过内部类ListItr来实现,其继承了单向迭代器Itr并实现双向迭代器接口ListIterator
ListItr类定义
private class ListItr extends Itr implements ListIterator<E>
支持指定cursor位置构造
ListItr(int index) {
      cursor = index;
}
previous和next方法设置lastRet不同,next方法是cursor未加1之前的值,而previous是cursor减1以后的值
public boolean hasPrevious() {
	    return cursor != 0;
	}
	public E previous() {
		checkForComodification();
        try {
                int i = cursor - 1;
                E previous = get(i);
                lastRet = cursor = i;
                return previous;
        } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
        }
}
set方法是在lastRet处修改该元素的值,向前遍历一次previous则为cursor-1,向后遍历一次则为cursor
public void set(E e) {
	    if (lastRet == -1)
		throw new IllegalStateException();
            checkForComodification();
	    try {
		AbstractList.this.set(lastRet, e);
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException ex) {
		throw new ConcurrentModificationException();
	    }
}
add方法在当前cursor位置添加,并将cusor加1
public void add(E e) {
        checkForComodification();
	try {
	    	AbstractList.this.add(cursor++, e);
	    	lastRet = -1;
	    	expectedModCount = modCount;
	} catch (IndexOutOfBoundsException ex) {
	    	throw new ConcurrentModificationException();
	}
}

总结

1. ArrayList内部通过数组方式实现,采用加倍策略而非指定常量扩容,指定位置添加采用平摊分析复杂度为O(1)
2. ArrayList中数组声明为transient不会序列化,重写了readObject和writeObject进行反序列化和序列化,保证只序列化有效大小的数组元素。
3. 迭代器支持fast-fail,当迭代过程中检测到容器结构发生变化添加或删除元素时,会抛出ConcurrentModificationException,通过内部modCount实现。调用迭代器自身remove方法和双向迭代器中add和set方法不会引起并发修改异常。
4. 迭代器中remove和set方法需要调用next或previous内部lastRet成员设置为有效索引才可以,并且调用完remove方法以后lastRet又重新设置为-1,不能直接反复调用。
参考
OpenJDK 源代码阅读之 ArrayList

ArrayList源码阅读