我这里阅读的是JDK17关于ArrayList的源码,不过思路都是一样的
简介
ArrayList 是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
ArrayList 继承了 AbstractList ,并实现了 List 接口。
属性设置
// 序列化 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 = {};
// 当前数据对象存放地方
transient Object[] elementData;
// 当前数组长度
private int size;
构造方法
- 带初始值的构造方法
传入一个初始值,对其进行判断,如果大于0,使用用户的参数初始化,如果等于0,使用空值,都不满足,抛出异常
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时,不传入参数,直接赋予空值
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
- 传入参数为集合的构造方法
这里先将集合转换成数组,在
size
进行非空判断后,如果传入的参数为 ArrayList,直接将转换为的数组赋值给elementData
,如果是其他类型,将转换为的数组复制到新的Object数组中并将其赋值给elementData
,如果size
为空,赋值为空
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
添加
- 无返回值的添加方法,接收三个参数
E e:要添加的元素
Object[] elementData:ArrayList 内部存储元素的数组
int s:当前 ArrayList 的大小(即元素个数)
将元素
e
添加到数组elementData
中,如果长度不够,调用row()
方法进行扩容
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
- 返回布尔值的添加方法,接收一个参数
和上面的
E
是一样的,modCount
是 AbstractList 中的一个属性,代表修改计数器,对修改次数进行记录,通过上一个add(E e, Object[] elementData, int s)
进行添加
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
- 插入到指定位置的添加方法
通过
rangeCheckForAdd()
方法对索引进行检查,如果小于0或者大于size
,抛出异常,对修改次数进行修改,检查数组是否需要扩容,之后对元素进行移动,插入新元素,修改size
public void add(int index, E element) {
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
扩容
- 对ArrayList的内部数组进行扩容
如果当前数组容量大于 0,按一定的规则计算新容量并扩容。
如果当前数组为空且不是默认的空数组,按一定的规则计算新容量并扩容。
如果当前数组是默认的空数组,直接创建一个新数组。
先获取当前数组容量,判断当前数组是否需要扩容,如果需要,计算所需扩容量,创建新数组并赋值数据,如果不需要返回默认空数组
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
图解