首先申明一下,此篇文章仅仅是我个人学习ArrayList源码后的学习总结,如果有错误,可以提出来探讨。
1.1 原理
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;//数组
public ArrayList(int initialCapacity) {//初始化容器的大小
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this(10);//默认是10
}
底层是使用数组和自动扩容来实现的。默认容量10,当然也可以自定义初始容量
1.2 结构
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
AbstractCollection是一个抽象类,它实现Collection接口。主要是对(add,remove)等操作做简单的实现。Collection接口继承Iterable接口, Collection接口主要是对(add,remove)等操作定义抽象方法。Iterable接口,只有一个iterator抽象方法,用来获得对应的迭代器。
(所以ArryList并不直接实现iterator接口,而是实现创建iterator的Iterable接口)。
AbstractList抽象类继承AbstractCollection抽象类,主要是在内部实现迭代器(Itr,ListItr),ArrayList类继承AbstractList抽象类,主要是对(add,remove)等操作的具体实现。
1.3 不常用方法:
1.3.1 retainAll(Collection<?>c)
如果list中的值在集合c中不存在,就删除。
1.3.2 trimToSize()
自动扩容会使数组的长度,比实际的数据的长度要大一些,
这时,可以采用此方法使数组的长度和数据的长度一致,减少空间。
1.4 List迭代器
Arrylist并不直接实现迭代器的接口(iterator),它实现了创建迭代器工厂的接口(iterable)。它通过内部类来实现迭代器的接口(iterator);支持对集合(容器)进行多种迭代器(Itr,ListItr),支持同时对容器进行多次遍历(每次遍历都会产生一个新迭代器)。
1.4.1 Itr
这是通用的迭代器。可以通过iterator()获得;主要提供3个方法:hasNext()、netx()、remove();
源码:
简单的说,在Irt中维护了一个当前指针cursor,通过cursor来遍历数组的。
private class Itrimplements Iterator<E> {
/**
* Index of element to bereturned by subsequent call to next.
*/
int cursor = 0;//遍历数组的指针,
/**
* Index of elementreturned by most recent call to next or
* previous. Reset to -1 if this element is deleted by a call
* to remove.
*/
int lastRet = -1;//调用next返回的元素的下标。(正常情况:cursor=lastRet+1);
/**
* The modCount value thatthe iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrentmodification.
*/
int expectedModCount = modCount;//线程一致性(如果你在遍历数组时,数组被外部改变了,就会报异常
public boolean hasNext() {
returncursor != size();
}
public E next() {
checkForComodification();//检查数组有没有被外部修改
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
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();
}
}
final void checkForComodification() {
if (modCount !=expectedModCount)
throw new ConcurrentModificationException();
}
}
1.1.1 ListItr
此迭代器是ArrayList扩展的。可以通过listIterator()获得,它除了从前往后遍历外,还能从后往前遍历。
源码:
private class ListItr extends Itrimplements ListIterator<E> {
ListItr(int index) {//对cursor重新赋值
cursor = index;
}
public boolean hasPrevious() {
returncursor != 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();
}
}
public int nextIndex() {
returncursor;
}
public int previousIndex() {
returncursor-1;
}
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();
}
}
public void add(E e) {
checkForComodification();
try {
AbstractList.this.add(cursor++, e);
lastRet = -1;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
从代码上看ListItr是继承Itr,它可以使用Itr所有的方法,同时又加了扩展,
其实也就是让cursor可以重新赋值了。相当于你遍历的初始位置可以自定义(开头,最后,中间的任意位置),同时又提供向前遍历的方法(previous()),比起Itr还多了一些add,set方法。