ArrayList实现
继承关系
java.lang.Object
-
java.util.AbstractCollection<E>
-
java.util.AbstractList<E>
- java.util.ArrayList<E>
实现接口
Serializable, Cloneable, Iterable<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 = Arrays.copyOf(elementData, newCapacity);
}
}
remove方法,移动index+1及其后面元素,并将最后一个元素设置为null,帮助GC回收
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); //elementData[index+1,size) -->elementData[index,size-1)
elementData[--size] = null; // Let gc do its work
return oldValue;
}
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 = new Object[arrayLength];
// Read in all elements in the proper order.
for (int i=0; i<size; i++)
a[i] = s.readObject();
}
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支持两种迭代器:
Iterator和
ListIterator(双向迭代),实现在
AbstractList中
Iterator通过内部类
AbstractList$Itr实现
Itr类定义
private class Itr implements Iterator<E>
属性包括
int cursor = 0; //当前遍历的下标
int lastRet = -1; //最近调用next或previous返回的下标,当调用自身remove方法删除元素后,重置为-1
int expectedModCount = modCount;
//用于检测遍历过程中并发修改
重要方法
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,下次接着调用就会抛异常。
ListItr类定义
private class ListItr extends Itr implements ListIterator<E>
支持指定cursor位置构造
ListItr(int index) {
cursor = index;
}
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,不能直接反复调用。
参考