ArrayList底层是一个数组,数组元素类型为object,支持动态扩容,所以ArrayList也相当于一个动态数组;ArrayList继承自 AbstractList,实现了 List 接口,允许 null 的存在;
接下来我们通过类层次结构、构造方法及常用方法三方面看ArrayList源码;
ArrayList继承了AbstractList,实现了List、RandomAccess、Serializable、Cloneable这些接口;
/**
* 存储ArrayList元素的数组,
* 添加到 ArrayList 中的元素数据(第一次添加元素时,空ArrayList会扩容到 DEFAULT_CAPACITY = 10 )
*/
transient Object[] elementData;
/**
* ArrayList大小,包含元素数量
*/
private int size;
构造方法 | 构造方法描述 |
---|---|
ArrayList() | 构造一个初始容量为10的空列表 |
ArrayList(int initialCapacity) | 构造具有指定初始容量的空列表 |
ArrayList(Collection extends E> c) | 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序 |
DEFAULTCAPACITY_EMPTY_ELEMENTDATA,使用无参构造方法创建ArrayList数组的时候,是一种懒加载模式,创建的时候不设置大小,而是在使用的时候设置大小;
//默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
//用于空实例的共享空数组实例,从0开始,按照1.5倍扩容
private static final Object[] EMPTY_ELEMENTDATA = {};
//共享的空数组对象,用户ArrayList() 构造方法,和EMPTY_ELEMENTDATA区分开,在第一次添加元素时,首次扩容为10
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
根据传入的初始化容量,创建Array数组,如果传入参数是大于等于0,则使用用户的参数初始化,如果传入参数小于0,则抛异常;
public ArrayList(int initialCapacity) {
//初始化容量>0时,创建Object数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
//初始化容量=0时,使用EMPTY_ELEMENTDATA对象
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
//初始化容量<0时,抛IllegalArgumentException异常
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
构造一个包含指定集合元素的列表,这些元素按照 collection 集合迭代器返回的顺序排列的
/**
* 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表
*/
public ArrayList(Collection<? extends E> c) {
//将C 转换为 object 数组
Object[] a = c.toArray();
if ((size = a.length) != 0) {
//判断集合元素是否为 Object[]类型,不是的话,会创建新的 Object[]数组,并把 elementData 赋值到新数组中,最后赋值给 elementData
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
//如果数组size = 0 ,则直接将空对象 EMPTY_ELEMENTDATA
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
顺序添加单个元素到数组
/**
* 在列表末尾添加元素
*/
public boolean add(E e) {
//增加数组操作次数
modCount++;
//添加元素
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
//如果容量不够,进行扩容
if (s == elementData.length)
elementData = grow();
//设置到末尾
elementData[s] = e;
//数量大小加一
size = s + 1;
}
插入单个元素到指定位置
public void add(int index, E element) {
// 校验位置是否在数组范围内
rangeCheckForAdd(index);
// 增加数组修改次数
modCount++;
//如果数组大小不够,进行扩容
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
//将 index + 1 位置开始的元素,进行往后挪
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
//设置到指定位置
elementData[index] = element;
//数组大小加一
size = s + 1;
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
批量添加多个元素,如果明确知道会添加多个元素时,使用该方法,避免使用单个元素添加带来的多次扩容;
public boolean addAll(Collection<? extends E> c) {
//转成 a 数组
Object[] a = c.toArray();
//增加操作次数
modCount++;
//如果 a 数组大小为 0 ,返回 ArrayList 数组无变化
int numNew = a.length;
if (numNew == 0)
return false;
//如果 elementData 剩余的空间不够,则进行扩容。要求扩容的大小,至于能够装下 a 数组。
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);
//将 a 复制到 elementData 从 s 开始位置
System.arraycopy(a, 0, elementData, s, numNew);
//数组大小加 numNew
size = s + numNew;
return true;
}
从指定位置开始批量添加多个元素
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
// 增加数组修改次数
modCount++;
//如果 a 数组大小为 0 ,返回 ArrayList 数组无变化
int numNew = a.length;
if (numNew == 0)
return false;
//如果 elementData 剩余的空间不够,则进行扩容,扩容的大小,至于能够装下 a 数组。
Object[] elementData;
final int s;
if (numNew > (elementData = this.elementData).length - (s = size))
elementData = grow(s + numNew);
/**
* 如果 index 开始的位置已经被占用,将原有元素向后移
*/
int numMoved = s - index;
if (numMoved > 0)
System.arraycopy(elementData, index,
elementData, index + numNew,
numMoved);
//将 a 复制到 elementData 从 s 开始位置
System.arraycopy(a, 0, elementData, index, numNew);
//数组大小加 numNew
size = s + numNew;
return true;
}
删除index位处的数据
public E remove(int index) {
//校验 index 不要超过 size
Objects.checkIndex(index, size);
final Object[] es = elementData;
//记录该位置的原值
@SuppressWarnings("unchecked") E oldValue = (E) es[index];
//快速移除
fastRemove(es, index);
//返回该位置的原值
return oldValue;
}
private void fastRemove(Object[] es, int i) {
//增加数组修改次数
modCount++;
//如果 i 不是最末尾的元素,则将 i + 1 位置的数组往前挪
final int newSize;
if ((newSize = size - 1) > i) // -1: size 是从 1 开始,而数组下标是从 0 开始
//把i+1位后的 newSize-i的数据往前移一位
System.arraycopy(es, i + 1, es, i, newSize - i);
//末尾置为 null
es[size = newSize] = null;
}
获取指定元素位置,找不到,返回-1
public int indexOf(Object o) {
return indexOfRange(o, 0, size);
}
int indexOfRange(Object o, int start, int end) {
Object[] es = elementData;
//null 的情况
if (o == null) {
//从start循环到end,如果数据为空,则返回对应下标
for (int i = start; i < end; i++) {
if (es[i] == null) {
return i;
}
}
//非 null 的情况
} else {
for (int i = start; i < end; i++) {
//调用目标函数的equals方法
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
查找元素最后一次出现位置
public int lastIndexOf(Object o) {
//范围内查询元素最后一次出现位置(即逆第一次出现位置)
return lastIndexOfRange(o, 0, size);
}
int lastIndexOfRange(Object o, int start, int end) {
Object[] es = elementData;
if (o == null) {
for (int i = end - 1; i >= start; i--) { // 倒序
if (es[i] == null) {
return i;
}
}
} else {
for (int i = end - 1; i >= start; i--) { // 倒序
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
克隆 ArrayList 对象
// ArrayList.java
public Object clone() {
try {
//调用父类,进行克隆
ArrayList<?> v = (ArrayList<?>) super.clone();
//拷贝一个新的数组
v.elementData = Arrays.copyOf(elementData, size);
//设置数组操作次数为0
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
创建一个新的更大的数组,然后将原数组复制到新数组中,最后返回新数组
以下是扩容核心代码:
//JDK 9
private Object[] grow() {
//调用 #grow(int minCapacity) 方法,要求扩容后至少比原有大1
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
//如果原容量大于0 ,或者数组不是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时,计算新的数组大小,并扩容
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity,
oldCapacity >> 1
return elementData = Arrays.copyOf(elementData, newCapacity);
//如果是 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 数组,直接创建新的数组
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
//JDK8
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//将 oldCapacity 右移一位,相当于 oldCapacity / 2
//将容量更新为 原容量 的 1.5 倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//判断 新容量 与 最小需要容量,如果新容量 < 最小需要容量,就把最小需要容量作为 新容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果 新容量 > MAX_ARRAY_SIZE,就 比较 minCapacity 和 MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//如果 minCapacity > MAX_ARRAY_SIZE,则 新容量为 Integer.MAX_VALUE,否则为 MAX_ARRAY_SIZE
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
“>>” 移位运算符:>>1 向右移一位相当于除以2,右移 N 位相当于除以2的 N 次方;
oldCapacity >> 1:oldCapacity 右移了一位,相当于 oldCapacity / 2;
set(int index, E element)方法,设置指定位置的元素
public E set(int index, E element) {
// 校验index不要超过 size
Objects.checkIndex(index, size);
// 获得index位置的原元素
E oldValue = elementData(index);
// 修改index位置为新元素
elementData[index] = element;
// 返回index位置的原元素
return oldValue;
}
get(int index) 方法获取指定位置的元素
public E get(int index) {
Objects.checkIndex(index, size);
//获得 index 位置的元素
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}