侧边栏壁纸
  • 累计撰写 7 篇文章
  • 累计创建 7 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

JDK源码学习-ArrayList

小白
2022-07-31 / 0 评论 / 0 点赞 / 113 阅读 / 5157 字

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

属性

image-1659279038039

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

构造方法

image-1659279067398

构造方法有三个

/**
 * 构造一个初始容量为 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;
    }
}

添加元素

image-1659279086798

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

image-1659279095836

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

获取元素

image-1659279106780

获取元素就更简单了,就使用传入的数组下标去数组取

快速失败

在add方法里面有看到有个modCount属性记录修改次数,在迭代的时候会判断此值,所以在迭代ArrayList的时候会抛出快速失败异常,以后再来具体分析快速失败的源码。

序列化

值得注意的是我们可以看到在ArrayList里面存储元素用的数组elementData有使用transient修饰,这样在序列化的时候就不会序列化这个属性了,那么内容不就丢失了吗?其实不会,因为ArrayList重写了writeObject和readObject方法,如下图: image-1659279114346

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

0

评论区