ArrayList无参构造添加元素源码解读

一、ArrayList无参构造add方法源码阅读

@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){
    ArrayList<Integer> arrayList = new ArrayList<>();
    ArrayList<Integer> list = new ArrayList<>();

    arrayList.add(1);
    arrayList.add(12);
    arrayList.add(13);
}

就用这个为测试吧。

对于arrayList.add(1)debug进去:

看到进来了这里:

1、来到Integer类方法内部

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

对于IntegerCache.cache[i + (-IntegerCache.low)];这里应该是将cache索引为i - IntegerCache.low的元素返回,对于cache这个数组存储的个数是2x128 = 28

也就是可以存储[-128,127]这些元素。

不信可以借助工具查看:

在这里插入图片描述

发现确实是这样。

2、来到ArrayList的add方法:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

size是什么?查看一下:

/**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */
private int size;

确实是大小,实锤了!!!

3、来到ensureCapacityInternal

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//elementData是Object[0]@1098,不知道是什么,minCapacity是1
}

4、来到calculateCapacity:

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//defaultcapacity_empty_elementdata这里是true的。
        return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY=10
       /*
     *DEFAULT_CAPACITY: Default initial capacity.
    private static final int DEFAULT_CAPACITY = 10;
       */
    }
    return minCapacity;
}

返回到:

ensureExplicitCapacity - > "Explicit是明确的意思"

来到:

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

minCapacity >elementData.length成立:

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

来到Arrays.copyof:

这里的original是一个对象吧

看到上一步是:

//类成员:transient Object[] elementData;

也就是elementData这个玩意,忍了很久了,之前一度怀疑这个是不是存储节点的数据,看看它的介绍发现果然是:

     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     翻译下:
     * 存储 ArrayList 元素的数组缓冲区。
     * 数组列表的容量是此数组缓冲区的长度。任何
     * 空的数组列表与元素数据 == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * 将在添加第一个元素时扩展到 DEFAULT_CAPACITY。

那么就继续copyof这个方法:

public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}

首先,分析一下这个类,返回的是一个T泛型类,那么也就是和elementData同一个类型的对象。

来到:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

应该是走(Object)newType == (Object)Object[].class是true,于是走这边(T[]) new Object[newLength]了,然后再来到:

        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));

这里很明显是将original的这里的内容拷贝到新的对象copy这个对象里了

,然后再返回新对象给:

public static <T> T[] copyOf(T[] original, int newLength) {

再回到:

private void grow(int minCapacity) {

返回copy给elementData.

再回到ArrayList的这个方法把里面的grow方法执行完再结束:

private void ensureExplicitCapacity(int minCapacity) {

结束。

再回到:

    private void ensureCapacityInternal(int minCapacity) {

再回到add方法将最后2行执行完就结束:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

二、回顾:

第一步先去确认下容器大小怎么样。

如果是第一次add,就给10个容量。人哈就去扩容也就是grow方法。

这里的grow是怎么扩容呢?

看看源码:

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)//如果比MAX_ARRAY_SIZE这个都大,那么就去
        newCapacity = hugeCapacity(minCapacity);//获取更大的容量
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

这里就是先按照增加原来的一半容量吧。从int newCapacity = oldCapacity + (oldCapacity >> 1)可以看出。>>这个符号就是有符号右移嘛,也就是除以2。

总结一下:

对于无参构造创建的ArrayList,一开始容器大小也就是size = 0,当要添加元素时,便是第一次添加元素,会扩容10个大小。后面继续添加元素时每次都会和之前的容量大小比较一下,刚好不够了再扩容,扩大50%。

先做数据的迁移,再做数据的添加。

如果是第二次扩容1,那么就是添加第11个元素时,先去grow一下,新创建数组大小为15的copy(也就是扩容),然后迁移数据。然后再将copy返回给elementData,再进行add,将元素添加到已经扩容了的elementData的末尾,可以使用这个来查看一下:

@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){
    ArrayList<Integer> arrayList = new ArrayList<>();
    ArrayList<Integer> list = new ArrayList<>();

    for (int i = 0; i <20; i++) {
        arrayList.add(i);
    }
}

过程和本文讲解的是一样的。

end

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值