ArrayList源码阅读
// 序列化ID
private static final long serialVersionUID = 8683452581122892189L;
// 默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//存储ArrayList元素的数组缓冲区。ArrayList的容量是该数组缓冲区的长度
transient Object[] elementData; // non-private to simplify nested class access
// 当前arraylist集合的大小,也就是elementData数组中数据元素的个数
private int size;
/**
* 形式一:携带一个int类型的参数,指定arraylist的初始容量
*
* initialCapacity为我们所指定的数组列表初始容量,
* 方法中对参数:initialCapacity的值进行了一系列判断,
* 当参数:initialCapacity的初始容量小于0时无意义,直接抛出非法参数异常。
* 当参数:initialCapacity大于0时,会直接创建一个Object类型的数组,数组的初始大小就是initialCapacity的值。
* 当initialCapacity等于0时,会直接将elementData指向EMPTY_ELEMENTDATA空数组。
*
*/
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);
}
}
/**
* 形式二:无参构造方法
* 在构造方法中直接将 elementData 指向 DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,
* 该ArrayList的size为初始值0。
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 形式三:携带一个Collection类型的参数
* 代码中首先将集合参数通过toArray方法转换成数组,并赋值给elementData,
* 然后对arraylist中的size进行赋值并判断size是否等于0.
* 当大小为0时,直接将elementData指向EMPTY_ELEMENTDATA空数组。
* 当size不为0时执行copyOf方法。
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
add()方法
/**
* 方式一:直接添加数据元素到arraylist的尾部
* 方法中首先调用到ensureCapacityInternal方法,将size+1作为参数传入。
* size用来表示当前数组列表的大小,也就是elementData中数组中元素的个数,
* 大小size+1就是确保数据元素添加成功的最小容量.
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* calculateCapacity方法中首先将elementData 和DEFAULTCAPACITY_EMPTY_ELEMENTDATA进行对比,
* 如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则执行 if 语句体的操作,
* 否则直接调用ensureExplicitCapacity方法,将最小容量minCapacity作为参数传入。
* 当我们通过ArrayList的无参构造方法创建ArrayList对象时,
* 在构造方法中会直接将elementData指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA。
* 当我们通过ArrayList的无参构造方法创建ArrayList对象后,再调用add方法的时候会执行if语句体操作,
* 将minCapacity 重新赋值为DEFAULT_CAPACITY和minCapacity中的最大值。
*/
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
/**
* 方法中首先将变量modCount自增1,
* modCount是用来标记当前arraylist集合操作变化的次数,在fail-fast机制中会有用到这个变量.
* 接着判断minCapacity - elementData.length 是否大于0,
* 当minCapacity - elementData.length大于0的时候说明当前elementData数组大小不够使用,
* 需要扩容,grow方法就是具体的扩容操作
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// 1.首先获取到elementData数组的长度,作为原容量
int oldCapacity = elementData.length;
// 2.新容量 = 原容量 + 原容量/2; 1.5倍扩容
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
// 3.若1.5倍扩容后还不够,则将最小容量作为新容量
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 4.限制最大容量
newCapacity = hugeCapacity(minCapacity);
// 5.进行原有数据元素copy处理
elementData = Arrays.copyOf(elementData, newCapacity);
}
remove()函数
/*
* 方式一:根据角标进行remove操作
*/
public E remove(int index) {
// 1. 对角标越界进行判断
rangeCheck(index);
// 2.modCount自增1
modCount++;
// 3.获取到指定下角标位置的数据
E oldValue = elementData(index);
// 4.计算需要移动的元素个数
int numMoved = size - index - 1;
if (numMoved > 0)
// 5. 指定角标位置后的元素前移一位
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 6.将size自减1,并将数组末尾置为null,便于垃圾回收
elementData[--size] = null; // clear to let GC do its work
// 7.最后将所要删除的数据元素return掉
return oldValue;
}
/*
* 方式二:根据数据元素进行remove操作
* 方法中首先对当前remove的数据元素进行null判断。
* 无论当前remove的数据元素是否为null,都需要一个for循环进行遍历操作,
* 注意if条件块的代码在数据元素为null和不为null两种情况下是不同的。
* 如果elementData数组中某一角标处的元素等于当前remove的数据元素,
* 会调用fastRemove方法进行具体remove操作,最后return true表示remove操作成功。
* 否则return false表示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) {
// 1.modCount的值自增1
modCount++;
// 2.计算需要移动的元素个数
int numMoved = size - index - 1;
// 3. 指定角标位置后的元素前移一位
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 4.将size自减1,并将数组末尾置为null,便于垃圾回收
elementData[--size] = null; // clear to let GC do its work
}
set()函数
/**
* set方法需要接受两个参数,第一个参数index为下角标,第二个参数element为数据元素,
* 表示将下角标index处的数据元素赋值为element。在方法中,首先对index下角标进行越界判断,
* 然后获取到角标index处的原数据元素oldValue,
* 接着将角标index处的数据元素赋值为element,最后将原有数据元素oldValue return掉。
*/
public E set(int index, E element) {
//对index进行越界检查
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
get()函数
public E get(int index) {
//对index进行越界检查
rangeCheck(index);
//返回数据
return elementData(index);
}
clear()函数
public void clear() {
//对modCount自增
modCount++;
// 遍历操作,将elementData数组角标元素置为null。
for (int i = 0; i < size; i++)
elementData[i] = null;
//将数组size设置为0
size = 0;
}
contains()函数
/*
* indexOf方法是将一个数据元素传入,返回该数据元素对应的下角标,
* 如果数据元素在当前arraylist中不存在,则返回-1。
* 也就是说当数据元素在当前arraylist中存在时,indexOf(o) >= 0成立,结果为true,
* 否则为false。
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* indexOf方法中对数据元素进行了null判断,两种情况下都进行了遍历操作,
* 两种情况下的if条件语句不同。
* 当满足条件时,直接将对应的下角标return掉,否则return -1,
* 表示当前arraylist中不存在该元素
*/
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;
}