本章分析List系列中的ArrayList,有些与PriorityQueue类似,比如底层同样采取数组存储元素,也涉及到扩容操作等;也有不同之处,比如PriorityQueue不允许存入的元素为null,而ArrayList允许将null元素存放其中。
一、 类实现/继承体系结构
为了对整个List实现/继承体系有个全貌,先将体系结构图画出来:
二、 关键数据成员
(1)存储结构
transient Object[]elementData; // non-private to simplify nested class access;
以数组作为底层存储结构,存放ArrayList链表中的元素
数组elementData的默认初始化大小(DEFAULT_CAPACITY)是10。
(2)数组存放的元素个数
private int size;
三、 构造函数
ArrayList提供了多种形式的构造函数,在此不一一列举,就参数来说,主要包括,数组链表(elementData)初始化大小(initialCapacity)值、其他集合
这里要讲下以下几个构造函数:
publicArrayList (Collection<? extends E> c):利用另一个集合初始化ArrayList,要求就是负责初始化集合中的元素类型是E或者是E的子类。
四、 一些链表操作
(1) void trimToSize():将ArrayList的存储空间压缩到size大小,将空闲空间还给系统
做法就是Arrays.copyOf(elementData, size)新生成一个数组,赋值给elementData;
(2) void sort(Comparator<? super E> c):对链表进行排序,调用了Arrays.sort接口
Arrays.sort((E[])elementData, 0, size, c);
这里有一点,因为ArrayList接口都不是线程安全的,在一个线程操作链表时,并不能防止其他线程也在操作链表,有可能在排序时,其他线程已经修改了链表,修改有可能导致排序结果不准确,所以,这时就需要抛出异常:
public void sort(Comparator<?super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw newConcurrentModificationException();
}
modCount++;
}
五、 增
(1) boolean addAll(Collection<? extends E> c):将容器c中元素添加到ArrayList的末尾
首先检查容量capacity,然后执行拷贝
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size +numNew); // Increments modCount
System.arraycopy(a, 0, elementData,size, numNew);
size += numNew;
System.arraycopy参数含义:
第一个参数:数据来源数组;
第二个参数:数据来源数组的起始拷贝索引index;
第三个参数:数据目标数组;
第四个参数:数据目标数组起始拷贝索引index;
第五个参数:拷贝元素的个数;
(2) boolean addAll(int index, Collection<?extends E> c):将容器c中元素添加到ArrayList中,添加的起始位置是在index处
如果index不是数组末尾,就涉及到两次拷贝:
if (size - index > 0)
System.arraycopy(elementData,index, elementData, index+numNew, numMoved);
System.arraycopy(a,0, elementData, index, numNew);
六、 删
(1) E remove(int index):删除位于index位置的元素
不可避免的,会将数组elementData 在index之后元素前移一个位置,复杂度O(n)
System.arraycopy(elementData,index+1, elementData, index, numMoved);
(2) boolean removeAll(Collection<?> c):删除ArrayList中的集合c中的元素,即求交集
这里使用了一个叫做batchRemove的私有函数:
private booleanbatchRemove(Collection<?> c, boolean complement) {
final Object[] elementData =this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r])== complement)
elementData[w++] =elementData[r];
} finally {
// Preserve behavioralcompatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData,r,
elementData,w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size;i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
七、 改
八、 查
peek():返回队列queue中index=0的元素,queue[0];如果为空,则返回null。
contains(Object o):
public booleancontains(Object o) {
return indexOf(o) != -1;
}
九、 遍历
ArrayList实现了内部类Itr:
private class Itrimplements Iterator<E>
ArrayList还实现了内部类ListItr,其继承自Itr,并实现了接口ListIterator:
private class ListItrextends Itr implements ListIterator<E>
而接口ListIterator继承自Iterator接口:interface ListIterator<E>extends Iterator<E>
所以,可以通过两种迭代器遍历ArrayList,分别对应到Itr和ListItr:
Iterator<String>iter = names.iterator();
ListIterator<String>iter = names.listIterator()/names.listIterator(1);
Itr就是通用的迭代器,提供hasNext和next接口:
public Iterator<E> iterator() {
return new Itr();
}
ListIterator针对ArrayList,除了提供hasNext和next接口,还提供遍历的起始点index,并且还可以逆序遍历:
public ListIterator<E> listIterator()/listIterator(index) {
return new ListItr(0)/ListItr(index);
}
ListIterator<String> iter = names.listIterator(3);
while (iter.hasPrevious()) {
System.out.println(iter.previous());
}
十、 子链表subList
ArrayList实现了List<E>subList(int fromIndex, int toIndex)
List<E>subList(int fromIndex, int toIndex)接口即返回一个新生成的子链表subList对象。