文档头
- Arraylist 是List接口实现类,是可扩容数组。允许空值,粗略地认为与Vector相同,不过是非同步的。
- capacity指定内部数组容量,可以自动增长。存入大量数据前可以ensureCapacity(),确保容量达到一定值,也可以称作扩容
- 非同步地, 多线程访问发生结构性修改时,必须外部同步操作;或者用Collections.synchronizedList。
- iterator()是fast-fail型的。 iterator生成后,除了iterator自己的add()或remove()方法,其它对实例的结构性修改都会报ConcurrentModificationException。
变量定义
- private static final int DEFAULT_CAPACITY = 10; // 默认容量 10
- private static final Object[] EMPTY_ELEMENTDATA = {}; // 空数组
- private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认容量的空数组
- transient Object[] elementData; // 存储数据的数组
- private int size; // 数据个数
构造方法
-
public ArrayList() { // 空参构造数组为{} this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
-
public ArrayList(int initialCapacity) { //initialCapacity > 0 时,创建长度为initialCapacity的数组; if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; // initialCapacity == 0 , 取{}; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { // initialCapacity < 0 时报错。 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
-
public ArrayList(Collection<? extends E> c) { // 将collection转换成数组赋给eleData elementData = c.toArray(); // 计算size, 判断size != 0, 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 { // size == 0时,取{}. // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
重要方法
-
ensureCapacity(int minCapacity) 扩容 在即将数据前先将数组扩容,可以避免数组频繁自动扩容影响效率。
public void ensureCapacity(int minCapacity) { int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY; if (minCapacity > minExpand) { // minCapacity 大于默认容量(10)时开始扩容 ensureExplicitCapacity(minCapacity); } } private void ensureExplicitCapacity(int minCapacity) { modCount++; // 增加modCount // overflow-conscious code if (minCapacity - elementData.length > 0) // 新容量 > 当前容量,开始扩容 grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量初始化为(旧容量 * 1.5) if (newCapacity - minCapacity < 0) // 新容量 < 指定的minCapacity时,新容量定为 // minCapacity。所以扩容后的大小为 minCapacity与(oldCapacity*1.5)较大值 newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: // 创建长度为newCapacity的新数组, 将数据复制到新数组。 elementData = Arrays.copyOf(elementData, newCapacity); }
Arrays.copyOf方法会创建容量为newCapacity的新数组,并将eleData的数据复制过来; 扩容的容量是 minCapacity与(oldCapacity * 1.5)较大值。
-
add(E e)
public boolean add(E e) { // 扩容, 然后在数组末尾添加元素 ensureCapacityInternal(size + 1); elementData[size++] = e; return true; }
-
add(int index, E element)
public void add(int index, E element) { // 判断index是否越界 rangeCheckForAdd(index); // 扩容 ensureCapacityInternal(size + 1); // Increments modCount!! // 将 index开始的元素,全部复制到index+1后,集体移动。 System.arraycopy(elementData, index, elementData, index + 1, size - index); // 赋值 index位置。 elementData[index] = element; size++; }
-
remove(int index)
public E remove(int index) { rangeCheck(index); // 判断 modCount++; E oldValue = elementData(index); // 获取原对象 int numMoved = size - index - 1; if (numMoved > 0) // 将index+1的一起移动到index,集体移动 System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // 将原先的末尾元素置null。 return oldValue; }
-
remove(Object o)
public boolean remove(Object o) { if (o == null) { // o为null时, 寻找第一个null的偏移量,调用fastRemove()删除 for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) // 寻找第一个的偏移量,调用fastRemove()删除 if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; } 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; // clear to let GC do its work }
-
addAll(Collection<? extends E> c)
public boolean addAll(Collection<? extends E> c) { // 转换为数组 Object[] a = c.toArray(); int numNew = a.length; // 扩容为size + c.length ensureCapacityInternal(size + numNew); // Increments modCount // 将a元素从0开始复制到 eleData,从size开始。 System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
ArrayList中频繁使用System.arraycopy对元素进行集体移位,removeAll操作与这个类似。
-
toArray()
public Object[] toArray() { // 将elementData元素复制进一个新数组 return Arrays.copyOf(elementData, size); }
public <T> T[] toArray(T[] a) { if (a.length < size) // a.length < size时, 将部分元素存储进新数组 return (T[]) Arrays.copyOf(elementData, size, a.getClass()); // a.length >= size 时, 将eleData数据复制进a, 不用创建新数组。 System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
第一种方式总会创建“安全”的新数组,并复制元素到新数组;第二张方式当 a.length < size时会创建新数组, 否则直接存在a中。
Iterator
private class Itr implements Iterator<E> {
int cursor; // next()方法返回元素的偏移量
int lastRet = -1; // 上一个返回元素的下标,也是remove()方法删除的位置
int expectedModCount = modCount; // modCount的期望值, 用作fast-fail
Itr() {}
public boolean hasNext() { //
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification(); // 判断modCount, 不匹配抛出异常
int i = cursor;
if (i >= size) // 是否越界
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1; // cursor指向下一个元素位置
return (E) elementData[lastRet = i]; // 返回元素, 并将返回元素位置记录
}
public void remove() {
if (lastRet < 0) // 上次没有返回元素, 报错
throw new IllegalStateException();
checkForComodification(); // 判断modCount
try {
ArrayList.this.remove(lastRet); // 调用外部remove()方法, 删除上一个返回
// 位置的元素
cursor = lastRet; // 指向后一个
lastRet = -1;
expectedModCount = modCount; // 重新记录expectedModCount
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
可以看到Iterator创建时会存储当前时刻的modcount,当执行next()、remove()时,会检测当前的modeCount和内部存储的expectedModCount相等,不相等时直接抛出ConcurrentModificationException。多线程同时访问ArrayLis并可能发生修改时t时,必须在外部同步或使用同步Wrapper。
Iterator执行next()时会返回eleData[cursor]处元素,将cursor记录于lastret,以便删除返回对象;然后cursor值加1,以便获取下一个对象 。。
在Iterator内部成功调用remove()方法会调用外部的remove(int index)方法,并重新赋值expectedModCount。
ListIterator
ListIterator接口继承了Iterator接口,提供更丰富的功能。可以双向遍历,也可以在遍历过程中插入元素、修改元素。
* Marker interface used by <tt>List</tt> implementations to indicate that
* they support fast (generally constant time) random access.
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
super();
cursor = index;
}
// 省略了很多。。。。。。。。。。
}
总结
- ArrayList由数组实现,添加、删除操作都是对数组元素的复制操作实现
- 扩容时新容量,大于等于原容量的1.5倍,当指定的新容量大于原容量1.5倍时,取指定容量;当添加元素时会ensureCapacity,容量不足时会自动扩容。 因此在添加大量元素前,应该手动指定容量,以免多次发生自动扩容。
- toArray()会分配新数组并返回Object[];toArray(T[] a)当 a.length < size时,创建新数组,并复制eleData的一部分,,否则直接将eleData数据存入a
- Iterator()方法返回Itr类实例,记录当前cursor、lastRet、expectModCount。cursor用于next()获取下一个元素;lastRet用于remove()删除上一次返回的元素,过程中会调用外部remove()方法并重新记录modCount;modCount在初始化Iterator时或remove()时被赋值,其余时候用来判定是否发生并发修改,有就抛出异常。
- ListIterator()提供更丰富的功能
其它
偶然发现 ArrayList实现了一个RandomAccess接口,
* Marker interface used by <tt>List</tt> implementations to indicate that
* they support fast (generally constant time) random access.
* for typical instances of the class, this loop:
* <pre>
* for (int i=0, n=list.size(); i < n; i++)
* list.get(i);
* </pre>
* runs faster than this loop:
* <pre>
* for (Iterator i=list.iterator(); i.hasNext(); )
* i.next();
* </pre>
RandomAccess是一个标记接口,表示一个类支持快速随机访问。 在遍历过程中用for (int i=0, n=list.size(); i++)形式会比用迭代器快。。