ArrayList这个类,对于Android开发者来说太简单不过了:它是一个集合类,用来存放元素。比如说经常的用法是这样:List list = new ArrayList();我们可以对list集合进行一些基本的操作——增删改查。当然这些只是停留于会用ArrayList,你是否了解ArrayList内部实现原理?你是否了解其内部增删改查机制?你是否对它的扩容机制了然于心?如果你知道的话,下面这些内容你可以略过了;不知道的话,我们继续开车。
一、ArrayList源码解析
打开Android SDK的ArrayList源码,我们首先从其构造函数入手:
1、构造函数
从源码中我们可以看到ArrayList有三个构造函数,分别如下:
a).无参构造函数
/**
* Constructs a new {@code ArrayList} instance with zero initial capacity.
*/
public ArrayList() {
array = EmptyArray.OBJECT;
}
其中,array是ArrayList的成员变量,为transient Object[] array;为一个数组
,所以我们知道ArrayList内部是由一个数组来实现的。
b).形参为一个整形的构造函数
/**
* Constructs a new instance of {@code ArrayList} with the specified
* initial capacity.
*
* @param capacity
* the initial capacity of this {@code ArrayList}.
*/
public ArrayList(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("capacity < 0: " + capacity);
}
array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
}
首先判断capacity是否小于0,如果小于0,则抛出IllegalArgumentException异常;如果等于0,则创建一个跟无参构造函数一样的数组;如果大于0,则创建大小为capacity数组。
c).形参为一个集合的构造函数
/**
* Constructs a new instance of {@code ArrayList} containing the elements of
* the specified collection.
*
* @param collection
* the collection of elements to add.
*/
public ArrayList(Collection<? extends E> collection) {
if (collection == null) {
throw new NullPointerException("collection == null");
}
Object[] a = collection.toArray();
if (a.getClass() != Object[].class) {
Object[] newArray = new Object[a.length];
System.arraycopy(a, 0, newArray, 0, a.length);
a = newArray;
}
array = a;
size = a.length;
}
首先判断collection是否为空,为空的话则抛出NullPointerException异常;反之,则将collection转换成一个数组赋值给局部数组a,然后判断a是否是Object数组类型,如Object数组类型,最后将a赋值给ArrayList的临时变量array,另外成员变量size的值等于数组a的长度。
接下来我们看下ArrayList是如何添加元素的:
2、ArrayList的add方法
ArrayList的add方法也有四种重载方式,我们分别来看下:
a)、形参为一个参数的(参数是一个Object)
/**
* Adds the specified object at the end of this {@code ArrayList}.
*
* @param object
* the object to add.
* @return always true
*/
@Override public boolean add(E object) {
Object[] a = array;
int s = size;
if (s == a.length) {
Object[] newArray = new Object[s +
(s < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : s >> 1)];
System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
a[s] = object;
size = s + 1;
modCount++;
return true;
}
首先将array赋值给局部a数组,size赋值给局部变量a,然后判断s是否等于a数组的长度,其实这里一般是相等的,不知道老外什么逻辑,进入if判断之后,创建一个newArray数组,其容量值通过一个三元表达式来判断,先判断是s的值是否小于MIN_CAPACITY_INCREMENT / 2,其中MIN_CAPACITY_INCREMENT默认的值为12,也即是判断s是否小于6,如果s的值小于6则新数组的大小为s+12,反之则新数组的大小为s+(s大小的一半).然后将a的元素赋值到newArray中,并且修改array及a的值。最后将object放到a[s]位置、size加1、modCout自增1,其中modCount是记录修改次数的。
b)形参为两个参数的
/**
* Inserts the specified object into this {@code ArrayList} at the specified
* location. The object is inserted before any previous element at the
* specified location. If the location is equal to the size of this
* {@code ArrayList}, the object is added at the end.
*
* @param index
* the index at which to insert the object.
* @param object
* the object to add.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || location > size()}
*/
@Override public void add(int index, E object) {
Object[] a = array;
int s = size;
if (index > s || index < 0) {
throwIndexOutOfBoundsException(index, s);
}
if (s < a.length) {
System.arraycopy(a, index, a, index + 1, s - index);
} else {
// assert s == a.length;
Object[] newArray = new Object[newCapacity(s)];
System.arraycopy(a, 0, newArray, 0, index);
System.arraycopy(a, index, newArray, index + 1, s - index);
array = a = newArray;
}
a[index] = object;
size = s + 1;
modCount++;
}
这个add方法的意思是说在index位置插入object值,也即是在指定位置插入某个值。首先将array赋值给a,size赋值给s,然后判断index是否越界,是的话抛出越界异常;反之往下走,如果s小于a的长度,则将a数组的index开始到s-index位置的元素赋值到a的index开始后的元素;如果s大于a的长度则创建一个newArray数组,其大小也是扩容机制后的大小,实现跟上面的一样,这里不再详述。然后将数组a中0到index位置的元素copy到newArrayList中,再把数组a中index到s-index位置的元素copy到newArrayList中,newArray赋值给array及a,最后将object放到a[s]位置上,size加1,modCount自增1。
c)、形参为一个参数的(是一个集合)
/**
* This method controls the growth of ArrayList capacities. It represents
* a time-space tradeoff: we don't want to grow lists too frequently
* (which wastes time and fragments storage), but we don't want to waste
* too much space in unused excess capacity.
*
* NOTE: This method is inlined into {@link #add(Object)} for performance.
* If you change the method, change it there too!
*/
private static int newCapacity(int currentCapacity) {
int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
return currentCapacity + increment;
}
/**
* Adds the objects in the specified collection to this {@code ArrayList}.
*
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
*/
@Override public boolean addAll(Collection<? extends E> collection) {
Object[] newPart = collection.toArray();
int newPartSize = newPart.length;
if (newPartSize == 0) {
return false;
}
Object[] a = array;
int s = size;
int newSize = s + newPartSize; // If add overflows, arraycopy will fail
if (newSize > a.length) {
int newCapacity = newCapacity(newSize - 1); // ~33% growth room
Object[] newArray = new Object[newCapacity];
System.arraycopy(a, 0, newArray, 0, s);
array = a = newArray;
}
System.arraycopy(newPart, 0, a, s, newPartSize);
size = newSize;
modCount++;
return true;
}
首先是将collection转成数组放在newPart中,newPartSize代表newPart数组的大小,然后将array赋值给局部数组a,size赋值给s,新数组的size等于s+newPartSize,然后判断新数组是否大于a.length,如果大于的话则根据新数组的size进行扩容,将a中的元素copy到newArray中,并且newArray赋值给array及a.再将newPart中的元素copy到a的s到newPartSize位置,size等于newSize,modCount自增1。
d)、在指定位置添加集合
/**
* Inserts the objects in the specified collection at the specified location
* in this List. The objects are added in the order they are returned from
* the collection's iterator.
*
* @param index
* the index at which to insert.
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || location > size()}
*/
@Override
public boolean addAll(int index, Collection<? extends E> collection) {
int s = size;
if (index > s || index < 0) {
throwIndexOutOfBoundsException(index, s);
}
Object[] newPart = collection.toArray();
int newPartSize = newPart.length;
if (newPartSize == 0) {
return false;
}
Object[] a = array;
int newSize = s + newPartSize; // If add overflows, arraycopy will fail
if (newSize <= a.length) {
System.arraycopy(a, index, a, index + newPartSize, s - index);
} else {
int newCapacity = newCapacity(newSize - 1); // ~33% growth room
Object[] newArray = new Object[newCapacity];
System.arraycopy(a, 0, newArray, 0, index);
System.arraycopy(a, index, newArray, index + newPartSize, s-index);
array = a = newArray;
}
System.arraycopy(newPart, 0, a, index, newPartSize);
size = newSize;
modCount++;
return true;
}
首先将size赋值给s,如果index越界,则抛throwIndexOutOfBoundsException异常。把collection转成数组放在newPart中,newPartSize代表newPart数组的大小,然后将array赋值给a,newSize等于s+newPart的长度,判断newSize是否小于a的长度,如果小于的话则直接a中index开始的元素放到index+newPartSize开始的位置;反之往下走,根据newSize进行扩容,创建newArray,再将a中0到index的元素copy到newArray,a中index后的所有元素copy到newArray中的index+newPartSize到s-index位置,最后再将newArray赋值给array及a,将newPart中的元素copy到a的index到newPartSize位置,size等于newSize,modCount自增1。
接下来我们来看下ArrayList是如何移除元素的:
3、ArrayList的remove方法
a)、形参为一个整形下标
/**
* Removes the object at the specified location from this list.
*
* @param index
* the index of the object to remove.
* @return the removed object.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || location >= size()}
*/
@Override public E remove(int index) {
Object[] a = array;
int s = size;
if (index >= s) {
throwIndexOutOfBoundsException(index, s);
}
@SuppressWarnings("unchecked") E result = (E) a[index];
System.arraycopy(a, index + 1, a, index, --s - index);
a[s] = null; // Prevent memory leak
size = s;
modCount++;
return result;
}
首先将array赋值给局部数组a,size赋值给s,假如index大于等于s,则是越界异常。然后将index开始的位置元素往前移一个位置,a[s]置空,size减1。modCount自增1。返回删除元素。
b)、形参为一个object
@Override public boolean remove(Object object) {
Object[] a = array;
int s = size;
if (object != null) {
for (int i = 0; i < s; i++) {
if (object.equals(a[i])) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++;
return true;
}
}
} else {
for (int i = 0; i < s; i++) {
if (a[i] == null) {
System.arraycopy(a, i + 1, a, i, --s - i);
a[s] = null; // Prevent memory leak
size = s;
modCount++;
return true;
}
}
}
return false;
}
首先将array赋值给局部数组a,size赋值给s,然后判断object是否为空,不为空的话则遍历a,当a[i]等于object的时候,将i位置之后的元素往前移一个位置,再将a[s]置空,size减1,modCount自增1,接着继续循环,直到遍历完为止。如果object为空的话,原理跟前面一样,这里不再讲述。
4、ArrayList的removeRange方法
@Override protected void removeRange(int fromIndex, int toIndex) {
if (fromIndex == toIndex) {
return;
}
Object[] a = array;
int s = size;
if (fromIndex >= s) {
throw new IndexOutOfBoundsException("fromIndex " + fromIndex
+ " >= size " + size);
}
if (toIndex > s) {
throw new IndexOutOfBoundsException("toIndex " + toIndex
+ " > size " + size);
}
if (fromIndex > toIndex) {
throw new IndexOutOfBoundsException("fromIndex " + fromIndex
+ " > toIndex " + toIndex);
}
System.arraycopy(a, toIndex, a, fromIndex, s - toIndex);
int rangeSize = toIndex - fromIndex;
Arrays.fill(a, s - rangeSize, s, null);
size = s - rangeSize;
modCount++;
}
首先判断fromIndex是否等于toIndex,如果等于直接返回。往下走,把array赋值给a,size赋值给s,如果fromIndex或toIndex大于s、fromIndex大于toIndex则抛出异常,然后将a中toIndex开始的元素往前移动rangeSize个位置并且a中s-rangeSize开始到s位置的元素置空,size变为s-rangeSize,modCount自增1。
5、ArrayList的set方法
/**
* Replaces the element at the specified location in this {@code ArrayList}
* with the specified object.
*
* @param index
* the index at which to put the specified object.
* @param object
* the object to add.
* @return the previous element at the index.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || location >= size()}
*/
@Override public E set(int index, E object) {
Object[] a = array;
if (index >= size) {
throwIndexOutOfBoundsException(index, size);
}
@SuppressWarnings("unchecked") E result = (E) a[index];
a[index] = object;
return result;
}
修改指定位置的元素,首先将array赋值给a,如果index大于size则抛出越界异常,result记录修改前位置元素值,然后才将该位置元素的值置为object,把result返回。
6、ArrayList的clear的方法
/**
* Removes all elements from this {@code ArrayList}, leaving it empty.
*
* @see #isEmpty
* @see #size
*/
@Override public void clear() {
if (size != 0) {
Arrays.fill(array, 0, size, null);
size = 0;
modCount++;
}
}
如果size不等于0,则用null填充各个位置的元素,size置为0,modCount自增1。
好了,ArrayList的源码分析就到这为止了,技术水平有限,不正之处欢迎批评指正。谢谢各位。