ArrayList源码相对来说较为简单,没有太多特别的设计,就是一个自动扩容的数组,自动扩容是指,ArrayList内部存储数据是使用的数组,当数组存储满了的时候再添加数据就会自动的创建一个更长的数组,并且将数据拷贝到新数组实现扩容。 下面开始分析一些ArrayList主要的方法。
属性

可以可以看到注释也写得很清楚,ArrayList是内部是使用elementData来存储元素,size是来存储数组里面存储了多少个数据了,以及还有默认的初始容量,EMPTY_ELEMENTDATA空数组实例,以及区特意开的空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA用来标识第一个元素添加时膨胀到DEFAULT_CAPACITY,下面的源码就会渐渐看到它实际使用了。
构造方法

构造方法有三个
/**
* 构造一个初始容量为 10 的空列表。
*
* note:无参的构造方法,可以通过代码看到elementData是赋值的DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空的数组,至于说为什么是构造一个初始值为10的是因为在扩容的时候有判断,可以看下面的add方法的说明
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 构造一个具有指定初始容量的空列表。
*
* note:带int类型的构造函数,可以指定存储数据的数组的初始大小,如代码所示它直接创建了一个长度为initialCapacity的数组用来存储数据
*
* @param initialCapacity 列表的初始容量
* @throws IllegalArgumentException 如果指定的初始容量为负
*
*/
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);
}
}
/**
* 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。
*
* note:将参数的集合转为数组,然后将数组里面的内容拷贝一份作为本List的elementData数据存储数组
*
* @param c 将其元素放入此列表的集合
* @throws NullPointerException 如果指定的集合为空
*/
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;
}
}
添加元素

可以看到add元素前有size的判断,如果满了就会调用grow方法进行扩容

就是增长原数组的长度右移一位(也就是原数组长度的一半),然后将原数组进行复制,并形成一个新长度的数组。 值得注意的是这里就有前面属性说的DEFAULTCAPACITY_EMPTY_ELEMENTDATA判断,也就是没有指定容量的默认容量增长判断。
获取元素

获取元素就更简单了,就使用传入的数组下标去数组取
快速失败
在add方法里面有看到有个modCount属性记录修改次数,在迭代的时候会判断此值,所以在迭代ArrayList的时候会抛出快速失败异常,以后再来具体分析快速失败的源码。
序列化
值得注意的是我们可以看到在ArrayList里面存储元素用的数组elementData有使用transient修饰,这样在序列化的时候就不会序列化这个属性了,那么内容不就丢失了吗?其实不会,因为ArrayList重写了writeObject和readObject方法,如下图:

可以看到它有一个一个循环写elementData里面的元素,当然读取的时候也有读取赋值给elementData了,代码就不截图了省些流量。
评论区