您的位置:首页 > 编程语言 > Java开发

Java集合框架(2)—ArrayList源码分析

2017-01-16 23:41 316 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java arraylist