作为以java为语言开发的android开发者,集合几乎天天都要打交道,无论是使用频率最高的ArrayList还是HashSet,都频繁的出现在平时的工作中。但是其中的原理之前却一直没深入探究,接下来记录一下这次自己学习ArrayList源码的过程。
一.构造方法:
private static final int DEFAULT_CAPACITY = 10;//默认数组长度
transient Object[] elementData; //空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //默认空数组
private static final Object[] EMPTY_ELEMENTDATA = {}; //空数组
/**
*创建一个空数组
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
*创建一个长度为输入长度initialCapacity的一个数组
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
首先看构造方法,其实构造方法很简单,就是创建一个数组。顾名思义,arraylist底层其实就是以数组进行实现的,普通的构造方法List list = new ArrayList();实现的就是创建一个空数组。而带参数的构造方法则是创建一个长度为输入长度的数组。
二.add方法:
//添加一个子项
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 对数组进行扩容判断
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//计算现在的数组和需要扩容的大小进行比较
}
private void ensureExplicitCapacity(int minCapacity) {
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); //新容量,对其进行移位计算
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); //经过激烈的大小比较,获取到一个新数组
}
add运算需要对当前的数组容量进行比较,如果大于当前容量,需要通过移位运算进行扩容,
int newCapacity = oldCapacity + (oldCapacity >> 1);
这行代码实现了扩容的功能,将原来的容量 加上 之前容量的一半(>>1移位运算等同于十进制中的/2),则扩容为原来的1.5倍。
随后再把原先的数组复制到新数组中,最后再添加新元素。
三.remove方法:
public boolean remove(Object o) {
if (o == null) { //对元素是否为空进行单独判断
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index); //找到指定元素跳转到删除的方法
return true;
}
} else {
for (int index = 0; index < size; index++)
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);//将删除位置后面的元素集体复制到需要删除的位置,也就是说将numMoved后面的所有元素整体前移一位。
elementData[--size] = null; // clear to let GC do its work
}
remove方法是比较方便理解的,就是通过for循环找到需要删除的位置,然后再通过数组的前移来将需要删除的元素移除,表面上是删除了某个元素,实际上是将它后面的所有元素往前移动了一位,最后将size减一,并且置空最后一个元素。
四.clear方法
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
这个没什么好说的,也就是通过for循环将数组中每个元素置空。