本文基于JDK1.8进行分析,由于篇幅有限,只着重分析核心方法。
先来个大纲方便各位客官快速获取所需:
ArrayList 其实是一个动态数组,数组作为其底层支撑,内部的数组实例是 Object[ ] 型的,所以允许所有元素,包括空值。ArrayList 是不同步的,建议在单线程环境中使用。
/**
* 默认的初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 用于空实例的共享空数组实例.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 共享空数组实例用于默认大小的空实例。
* 与EMPTY_ELEMENTDATA区分开来,以知道在添加第一个元素时要扩大多少。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* ArrayList的元素存储在其中的数组缓冲区。
* ArrayList的容量是这个数组缓冲区的长度。
* 当添加第一个元素时,任何具有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList将展开为DEFAULT_CAPACITY。
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 包含元素的大小
*
* @serial
*/
private int size;
elementData
为数组缓冲区。 /**
* 带有初始化容量的构造函数
*
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {//如果该容量大于0
this.elementData = new Object[initialCapacity];//用该容量初始化数组
} else if (initialCapacity == 0) {//如果为0
this.elementData = EMPTY_ELEMENTDATA;//初始化空的数组
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
如果传入容量不为0,就用该容量进行初始化数组,否则初始化为空数组。
/**
* 默认构造函数
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//构造空的数组缓冲区
}
构造空的数组。
/**
* 包含指定集合的构造函数
*
*/
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)//是否为Object数组
elementData = Arrays.copyOf(elementData, size, Object[].class);//继续复制不为Object的数组
} else {
// 设置元素数组为空
this.elementData = EMPTY_ELEMENTDATA;
}
}
先将集合转换为数组类型,然后保存到 elementData
中
/**
* 添加元素
*
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 增加modCount!
elementData[size++] = e;//添加到数组缓冲区中
return true;
}
调用ensureCapacityInternal方法
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
继续调用ensureExplicitCapacity()和calculateCapacity()方法
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//判断是否为空数组
return Math.max(DEFAULT_CAPACITY, minCapacity);//取较大值
}
return minCapacity;
}
该方法能够返回指定容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//结构性加1
// overflow-conscious code
if (minCapacity - elementData.length > 0)//如果添加元素后长度大于数组缓冲区长度
grow(minCapacity);//进行扩容操作
}
1)结构性加1。
2)如果添加元素后长度大于数组缓冲区长度,进行扩容操作。
/**
* 增加容量以确保它至少能容纳最小容量参数指定的元素数量。
*
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//旧数组容量
int newCapacity = oldCapacity + (oldCapacity >> 1);//新数组容量等于旧数组容量的1.5倍
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);//拷贝扩大容量
}
1)新的数组容量扩大为原来的1.5倍。
2)如果超出最大数组容量,重新赋值新数组容量大小。
3)将元数组重新拷贝到容量为的newCapacity的数组中。
/**
* 用指定的元素替换掉在列表中指定位置的值
*/
public E set(int index, E element) {
rangeCheck(index);//越界检查,超出会抛出 IndexOutOfBoundsException
E oldValue = elementData(index);//保存指定位置的旧值
elementData[index] = element;//替换为新值
return oldValue;//返回旧值
}
1)检查越界否。
2)保存旧值,替换新值到指定位置。
3)返回原位置旧值。
/**
* 返回元素在数组中的位置
*
*/
public E get(int index) {
rangeCheck(index);//越界检查,超出会抛出 IndexOutOfBoundsException
return elementData(index);//调用elementData方法
}
1)先判断是否越界,然后调用elementData方法。
2)elementData方法里面直接返回该索引在数组中的值。
/**
* 移除在数组中指定位置的元素
*
*/
public E remove(int index) {
rangeCheck(index);//越界检查,超出会抛出 IndexOutOfBoundsException
modCount++;//结构性加1
E oldValue = elementData(index);//保存指定位置值
int numMoved = size - index - 1;//需要移动的个数
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);//从要移除位置的后一位重新复制到数组中
elementData[--size] = null; // 为方便进行 GC
return oldValue;//返回旧值
}
1)进行越界检查,结构性加1 。
2)计算需要移动的位置个数,如果大于0,就重新从移除位置后一位拷贝剩下数组元素。
3)把数组最后一个元素置空,方便进行GC。
4)返回旧值。
/**
* 返回此列表中第一次出现指定元素的索引
*
*/
public int indexOf(Object o) {
if (o == null) {//如果为空
for (int i = 0; i < size; i++)//遍历数组
if (elementData[i]==null)//找到第一个为null的位置
return i;
} else {//如果不为空
for (int i = 0; i < size; i++)//照样遍历
if (o.equals(elementData[i]))//找到与指定值相等的序列
return i;//返回序列号
}
return -1;//如果不存在,返回-1
}
1)指定元素为空,遍历找到空值,否则遍历找到相等值的序列。
2)在数组中没找到返回-1。
JAVA之路路漫漫,吾将上下而求索,希望和大家一起交流进步!