ArrayList源码简读
Ctrl+鼠标左键进入源码,以下来自jdk11:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
ArrayList继承了AbstractList,实现了 List<E>
, RandomAccess, Cloneable, Serializable
- List集合实现RandomAccess接口,就能支持快速随机访问 。
- 实现 Cloneable接口后,在类中重写Object中的clone方法,然后调用clone方法克隆。
- 实现了Serializable 接口,这意味着ArrayList支持序列化。
1.1 ArrayList类成员变量
// 序列化验证版本一致
private static final long serialVersionUID = 8683452581122892189L;
// 默认容量
private static final int DEFAULT_CAPACITY = 10;
// 空数组
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
// 初始化ArrayList的容器
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
// ArrayList集合中的核心数组
transient Object[] elementData;
// 记录数组中存储个数
private int size;
// 数组最大长度(ArrayList中没有用到这个常量,我没搜到)
private static final int MAX_ARRAY_SIZE = 2147483639;
1.2 ArrayList集合类的构造方法
- 无参数构造方法
文档说ArrayList默认长度为十。其实默认情况为空,调用了add方法才给十。
public ArrayList() {
// 初始化ArrayList中的elementData为长度为0的空数组。
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 参数为整型的构造方法
public ArrayList(int initialCapacity) {
// 初始化容量大于0才能构造成功
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else {
// 传负数则抛异常
if (initialCapacity != 0) {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
// 传0
this.elementData = EMPTY_ELEMENTDATA;
}
}
- 参数为Collection对象的构造方法
public ArrayList(Collection<? extends E> c) {
// 将传入的集合数据拷贝出来,放在当前集合的elementData中
this.elementData = c.toArray();
// 传入的集合有数据
if ((this.size = this.elementData.length) != 0) {
// 判断传入的集合数据是不是和Object[]一个类型,不是就给他转成Object[]类型
if (this.elementData.getClass() != Object[].class) {
this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
}
// 传入的集合没有数据
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
1.3 ArrayList集合类的方法add()
- add(E e)
public boolean add(E e) {
// 此变量来自父抽象类AbstractList,代表ArrayList集合的修改次数。
++this.modCount;
// 调用了重载方法
this.add(e, this.elementData, this.size);
return true;
}
- add(E e, Object[] elementData, int s)
private void add(E e, Object[] elementData, int s) {
// 容量等于已存数组长度(再添加一个就超长啦)
if (s == elementData.length) {
// 扩容
elementData = this.grow();
}
// 添加
elementData[s] = e;
this.size = s + 1;
}
- grow
private Object[] grow() {
// 调用重载方法
return this.grow(this.size + 1);
}
- grow(int minCapacity)
private Object[] grow(int minCapacity) {
// 老数组扩容后得到新数组,将老数组元素复制给新数组。copyOf内部会创建新数组。
return this.elementData = Arrays.copyOf(this.elementData, this.newCapacity(minCapacity));
}
- newCapacity(int minCapacity)
如果new无参构造后一直调用add方法。第一次进newCapacity方法,minCapacity为1,第二次进minCapacity为11。
private int newCapacity(int minCapacity) {
int oldCapacity = this.elementData.length;
// 新的容量 = 老 + (老的 / 2)。二进制右移动一位除以2,10进制右移一位除以10,比如:100右移变成10。
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 参数传入的容量比新容量大
if (newCapacity - minCapacity <= 0) {
// 地址值相同,第一次扩容,因为扩容一次Arrays.copyOf返回新数组
if (this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 这里是第一次扩容,默认为10
return Math.max(10, minCapacity);、
// 传入扩容长度小于0抛出异常
} else if (minCapacity < 0) {
throw new OutOfMemoryError();
} else {
// 使用传入参数作为扩容长度
return minCapacity;
}
} else {
// 计算出来的容量比传入容量大,但需要比2147483639小,否则
return newCapacity - 2147483639 <= 0 ? newCapacity : hugeCapacity(minCapacity);
}
}
- hugeCapacity(int minCapacity)
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) {
throw new OutOfMemoryError();
} else {
return minCapacity > 2147483639 ? 2147483647 : 2147483639;
}
}
1
1
1
1
1
1
1
1
1
1