ArrayList是Java容器类中最重要的类之一,我将根据ArrayList源码,结合自己的认识,学习ArrayList的实现,以点破面,以期对Java集合类有一个全面的深入。
以下是ArrayList源代码的outline:
1,类定义:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
ArrayList继承AbstractList,实现List,RandomAccess,Cloneable,java.io.Serializable接口
2,elementData
transient Object[] elementData;
ArrayList实际数据存储结构,transient是一个关键词:Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。
3,size
private int size;
ArrayList包含元素的个数
4,构造器
有参构造器,设置了初始容量
public ArrayList(int initialCapacity)
无参构造器,初始容量默认为10
public ArrayList()
元素是集合类的构造器
public ArrayList(Collection<? extends E> c)
5,trimToSize
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
将ArrayList的容量压缩到目前所包含元素的个数,即最小化容量
6,扩容相关
ArrayList最大的特征就是可以在初始化之后仍能改变大小。因此改变容量是其核心操作。与扩容相关的方法和变量如下:
变量:
1)size:size自然是非常关心的域
2)MAX_ARRAY_SIZE:最大容量,由JVM设定,
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
Integer,MAX_VALUE是2^32-1,至于为什么要再减8,不是很清楚。
3)minCapacity:经常作为参数传入扩容函数,是扩容后的容积不能小于这个值。
方法:
//保证容量不小于minCapacity,如果目前容量小于,会调用ensureExplicitCapacity()扩容
public void ensureCapacity(int minCapacity)
private void ensureCapacityInternal(int minCapacity)
//执行扩容到minCapacity,内部是调用grow()函数扩容
private void ensureExplicitCapacity(int minCapacity{
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/************important**************/
//扩容核心函数,通过创建一个新的大容量数组,然后将旧数组复制到新数组中,改变引用实现
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
//其中使用到hugeCapacity()函数,是用于处理minCapacity超出MAX_ARRAY_SIZE的情况
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
7,整体操作
//1,查询ArrayList元素数量
public int size() {
return size;
}
//2,查询是否为空
public boolean isEmpty()
return size == 0;
}
//3,clone
public Object clone()
//4,toArray转化成一个数组
public Object[] toArray()//Object实现
public <T> T[] toArray(T[] a)//泛型实现
8,数据操作
//0,索引越界检查,被其他函数调用的私有方法,如果越界会抛异常
private void rangeCheck(int index){
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void rangeCheckForAdd(int index)
//1,查询是否包含某元素
public boolean contains(Object o){
return indexOf(o) >= 0;
}
//2,查询元素的第一次出现的索引,可以查空元素,不存在的元素返回-1
public int indexOf(Object o){
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
//3,查询元素的最后一次出现的索引,可以查空元素,不存在的元素返回-1,实现和上一个基本一样,遍历顺序相反而已
public int lastIndexOf(Object o)
//4,根据索引查元素
public E get(int index)
//5,根据索引设置元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
//6,插入到尾,内部要调用扩容函数,这时候可以理解一系列扩容方法的意义,每次可能需要扩容的时候,根据实际元素数量和现有容量比较看是否真的需要扩容,如果需要就执行扩容,如果不需要,保持当前容量。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//7,向指定索引位置插入元素,观察它的实现,是先将原有数组中元素,想后移动一格,(通过复制数组函数实现),然后将带插入元素复制给空出的位置。
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
//8,删除索引位置元素,和插入元素方法类似,使用数组复制操作移动一格,尾元素清空
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
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
return oldValue;
}
//9,删除第一个指定元素,删除成功返回true,没有这个元素,返回false
public boolean remove(Object o)
//10,快速删除,不反回bool值,实际上上面的函数是调用快速删除的
private void fastRemove(int index)
//11,批量插入,插入集合类
public boolean addAll(Collection<? extends E> c)
//12,插入集合类到指定位置
public boolean addAll(int index, Collection<? extends E> c)
//13,删除指定范围内元素
protected void removeRange(int fromIndex, int toIndex)
//14,删除所有参数中有的元素
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
//15,删除所有参数中没有的元素
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
//16,上两个函数都调用了
private boolean batchRemove(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 behavioral compatibility 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;
}
9,流操作
ObjectInputStream和ObjectOutputStream是针对类对象的输入输出流,配合ArrayList可以组成灵活的操作,ArrayList有两个和他们相关的方法:
//1,将ArrayList中元素些入到输出流中
private void writeObject(java.io.ObjectOutputStream s)
//2,将输入流中的元素读到ArrayList中
private void readObject(java.io.ObjectInputStream s)
//具体实现暂不深究,在深入研究输入输出流时再学习
10,List转化与ListIterator
//返回从特定位置开始的迭代器ListIterator
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
//返回从头开始的迭代器ListIter
public ListIterator<E> listIterator() {
return new ListItr(0);
}
//返回一个普通迭代器
public Iterator<E> iterator() {
return new Itr();
}
//Itr和ListItr是Iterator和ListIterator接口的实现类,详情需要学习迭代器相关内容,再做解释。
//子List
public List<E> subList(int fromIndex, int toIndex) {
//检测参数是否合规
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
11,函数式编程相关
在Java1.8中加入了对函数式编程的一些支持,ArrayList也有一些相应方法,需要理解函数相关接口才好理解。暂跳过。
在http://ifeve.com/有很多相关的中文博客
12,sort
跟据Comparator进行排序
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
总结,通读了一遍ArrayList源码,发现了不少精巧的设计,加深了对容器类的理解。后续要继续努力学习其他源码——2017/1/16