集合篇之ArrayList

一、源码如何分析?

1.成员变量

2.构造方法

3.关键方法

        一些添加的方法。

二、debug看源码

我们给出下面代码:

    public void test01() {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        for (int i = 2; i <= 10; i++) {
            list.add(i);
        }
        list.add(11);
    }

1.第一次添加数据

1. 添加方法:

2. 确保内部容量:

3. 计算容量:

4. 确保真正的容量:

5. 扩容的方法:

围绕着这5个方法进行讲解:

        首先,add()方法里面先执行ensureCapacityInternal(size + 1); 这里的size是0,因为数组是空的,所以传入到ensureCapacityInternal()方法的参数就是minCapacity == 1

        其次,我们就需要计算容量,在calculateCapacity()方法中,里面的传入的两个参数,其中第一个参数elementData的值,在ArrayList() 构造方法里面已经赋过值了,就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,第二个参数就是前面的 1 。所以if里面判断正确,返回最大值,其中DEFAULT_CAPACITY = 10,所以10>1,最后返回的也就是10

        然后,我们在ensureExplicitCapacity()中这个方法,传入的minCapacity这个参数也就是 10。因为在if判断中,条件成立,也就是说容量不够,需要扩容了。

        最后,进入grow()方法,其中因为oldCapacity=0,newCapacity计算得出也是0。第一个条件判断就是0-10<0,所以把10赋值给newCapacity,第二个是数组容量最大的安全校验(暂时不用),最后一行代码也就是数组的拷贝,把elementData的容量变成了 10 。

        这样,我们的数组第一次扩容就这样说完了,我们回到add方法,elementData[size++] = e,这行代码就是把下标为0的位置给了元素1,然后size+1,说明数组有一个元素了。

2.第二次添加数据

        我们第二次添加是用for循环,添加了9个元素,我们分析这个过程。

        首先,for循环添加第一个元素的时候,ensureCapacityInternal(size + 1); 这里的size是1,因为数组之前添加了一个元素进行了size++,所以传入到ensureCapacityInternal()方法的参数就是minCapacity == 2。

        其次,在计算容量的时候,elementData已经不是默认的了,所以直接返回minCapacity。

        然后,我们在ensureExplicitCapacity()中这个方法里面,在if判断里面,其中minCapacity是等于2的,elementData.length在第一次添加数据的时候,已经扩容为10了,所以2-10<0,不需要扩容了。在代码里面,for循环添加了9个元素,执行流程都一样。

        最后,在add方法里面,把数据添加到数组后进行size+1。

3.第三次添加数据

        我们第三次添加一个元素,其中数组已经有10个元素了,我们分析这个过程。

        首先,ensureCapacityInternal(size + 1); 这里的size是10,因为数组里面有了10个元素,所以传入到ensureCapacityInternal()方法的参数就是minCapacity == 11。

        其次,在计算容量的时候,elementData已经不是默认的了,所以直接返回minCapacity。

        然后,我们在ensureExplicitCapacity()中这个方法,传入的minCapacity这个参数也就是 11。因为在if判断中,条件成立11-10>0,也就是说容量不够,需要扩容了。

        最后,进入grow()方法,其中因为oldCapacity=10, oldCapacity >> 1也就是右移一位也就是5,newCapacity计算得出是15。第一个条件判断就是15-10>0,直接走过该判断,最后一行代码也就是数组的拷贝,把elementData的容量变成了 15 。

         这样,我们的数组扩容就完成了。

三、面试题

1. ArrayList底层的实现原理是什么?

  • 底层数据结构

ArrayList底层是用动态的数组实现的

  • 初始容量

ArrayList初始容量为0,当第一次添加数据的时候才会初始化容量为10

  • 扩容逻辑

ArrayList在进行扩容的时候是原来容量的1.5倍,每次扩容都需要拷贝数组

  • 添加逻辑

    • 确保数组已使用长度(size)加1之后足够存下下一个数据

    • 计算数组的容量,如果当前数组已使用长度+1后的大于当前的数组长度,则调用grow方法扩容(原来的1.5倍)

    • 确保新增的数据有地方存储之后,则将新元素添加到位于size的位置上。

    • 返回添加成功布尔值。

2.  ArrayList list=new ArrayList(10)中的list扩容几次?

该语句只是声明和实例了一个 ArrayList,指定了容量为 10,未扩容。

  • 23
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值