JavaSE -- ArrayList扩容原理

目录

ArrayList扩容原理

源码

一、追进ArrayList源码

一、1. 追入:DEFAULTCAPACITY_EMPTY_ELEMENTDATA

二、第一次追进add源码

二、1. 追入:ensureCapacityInternal

 二、1.1. 追入:ensureExplicitCapacity

二、1.1.1. 追入:grow

第一遍追进之后数据的改变:

 三、第二次追进add源码

三、1. 追入:ensureCapacityInternal

 三、1.1. 追入:ensureExplicitCapacity

第二遍追进之后数据的改变:

第十遍追进之后数据的改变:

四、第十一次追进add源码

四、1. 追入:ensureCapacityInternal

 四、1.1. 追入:ensureExplicitCapacity

四、1.1.1. 追入:grow

总结

 面试时参考话术

ArrayList和 LinkedList 区别?


ArrayList扩容原理

1.ArrayList底层数据结构是数组!!!

2.数组的特点:固定长度,顺序存储,有下标,可重复。

代码

源码

一、追进ArrayList源码

        得到:

一、1. 追入:DEFAULTCAPACITY_EMPTY_ELEMENTDATA

         得到:-- 意思是:创建一个final修饰的Object类型的空的常量数组。

 总结,将空数组赋值给elementData这个属性。

        此时elementData数组是空的。

        DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组也是空的。


二、第一次追进add源码

         得到:

        (E e):就是你传入的 "aa" 。

        size:现在等于0。

二、1. 追入:ensureCapacityInternal

         得到:

        minCapacity:就等于 (size + 1)。-- 现在等于1。

        然后利用 if 判断,前面提到过,elementData是DEFAULTCAPACITY_EMPTY _ELEMENTDATA赋值得到的,所以现在它们两个相等。

        条件成立,就进入,Math.max (DEFAULT_CAPACITY, minCapacity)意思是取括号里的较大的值,咱们现在知道minCapacity的值是1,所以现在追进DEFAULT_CAPACITY的源码去看看:

        DEFAULT_CAPACITY的值是10。

        所以这行代码的意思是:

        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

        将10重新赋值给minCapacity。

        此时 minCapacity:等于10。

继续执行下一条语句:

 二、1.1. 追入:ensureExplicitCapacity

         此时 minCapacity = 10。

         第一条语句:modCount++;追进去看看:

         发现 modCount = 0。

         然后判断 minCapacity - elementData.length 是否大于 0 。因为前面说过elementData数组是空的,所以 10 - 0 是大于 0 的。

         条件成立,执行grow(minCapacity);

二、1.1.1. 追入:grow

注意:重点来了

        此时 minCapacity = 10。

语句:int oldCapacity = elementData.length;

        此时 oldCapacity = 0。

语句:int newCapacity = oldCapacity + (oldCapacity >> 1);

        位运算符:>> 意思是 / 2。 << 的意思是 * 2。

        此时 newCapacity = 0。

语句:if (newCapacity - minCapacity < 0)

                        newCapacity = minCapacity;

        判断 0 - 10 是否小于 0 。

        条件成立,执行:newCapacity = minCapacity;

        此时 newCapacity = 10。

语句:if (newCapacity - MAX_ARRAY_SIZE > 0)

                        newCapacity = hugeCapacity(minCapacity);

        判断 10 - MAX_ARRAY_SIZE 是否大于 0。

        MAX_ARRAY_SIZE = 2147483639。

        条件不成立,不执行:newCapacity = hugeCapacity(minCapacity);

        继续往下走。

语句:elementData = Arrays.copyOf(elementData, newCapacity);

        新数组 = Arrays.copyOf(旧的数组,新数组的长度):意思是复制数组,将旧数组复制到新的数组。

        此时 elementData 数组长度为 10。

        然后返回到 二、第一次追进add源码 执行下一条语句

        elementData[size++] = e;

        前面说过 size = 0;e = "aa";

        所以:elementData[0] = "aa";

        然后size++

        此时 size = 1。


第一遍追进之后数据的改变:

size = 1。

elementData 数组长度为 10。

newCapacity = 10。

modCount = 1。


 三、第二次追进add源码

         得到:

 

         此时 size = 1。

三、1. 追入:ensureCapacityInternal

         此时 minCapacity = size + 1。

         minCapacity = 2。

         判断 elementData 和 DEFAULTCAPACITY_EMPTY _ELEMENTDATA是否相等,因为经过第一次赋值导致 elementData 已经是 10了。所以条件不成立,不执行里面的语句。

         继续执行下一条语句。

 三、1.1. 追入:ensureExplicitCapacity

         得到:

        此时 modCount = 1。

        判断 minCapacity - elementData.length 是否大于 0 。

        因为此时elementData数组长度为 10。所以条件不成立,不执行里面语句。

        所以此时返回到 三、第二次追进add源码 执行下一条语句。

        elementData[size++] = e;

        前面说过 size = 1;e = "bb";

        所以:elementData[1] = "bb";

        然后size++

        此时 size = 2。

第二遍追进之后数据的改变:

size = 2。

elementData 数组长度为 10。

newCapacity = 10。

modCount = 2。

第十遍追进之后数据的改变:

size = 10。

elementData 数组长度为 10。

newCapacity = 10。

modCount = 10。

四、第十一次追进add源码

 

         得到:

         此时 size = 10 。

四、1. 追入:ensureCapacityInternal

        此时 minCapacity = size + 1 。

        minCapacity = 11 。

        判断 elementData 和 DEFAULTCAPACITY_EMPTY _ELEMENTDATA是否相等,因为经过前面赋值导致 elementData 已经是 10了。所以条件不成立,不执行里面的语句。

        继续执行下一条语句。

 四、1.1. 追入:ensureExplicitCapacity

        此时 modCount = 10 。

        判断 minCapacity - elementData.length 是否大于 0 。

        因为 minCapacity = 11 。elementData 数组长度为 10 。所以条件成立,执行里面的语句。

四、1.1.1. 追入:grow

重点:

        此时 minCapacity = 11 。elementData.length = 10 。

语句:int oldCapacity = elementData.length;

        此时 oldCapacity = 10 。

语句:int newCapacity = oldCapacity + (oldCapacity >> 1);

        意思是:newCapacity = 10 + (10 除以 2)

        此时 newCapacity = 15 。

语句:if (newCapacity - minCapacity < 0)

                        newCapacity = minCapacity;

        判断 15 - 11 是否小于 0 。

        不小于,所以不执行里面的语句:newCapacity = minCapacity;

语句:if (newCapacity - MAX_ARRAY_SIZE > 0)

                        newCapacity = hugeCapacity(minCapacity);

        判断 15 - MAX_ARRAY_SIZE 是否大于 0。

        MAX_ARRAY_SIZE = 2147483639。

        条件不成立,不执行:newCapacity = hugeCapacity(minCapacity);

        继续往下走。

语句:elementData = Arrays.copyOf(elementData, newCapacity);

        意思是:新数组 = Arrays.copyOf(老数组,新数组长度);

        elementData = Arrays.copyOf(elementData,15);

        所以这是后 elementData 数组长度为 15 。

        然后返回到 四、第十一次追进add源码 执行下一条语句

        elementData[size++] = e;

        所以:elementData[10] = "第十一次";

        然后size++

        此时 size = 11。

总结

1、底层创建了一个 Object[] 的数组。数组名:elementData。此数组中没有元素。

2、通过 List.add 调用 grow() 扩容方法,数组长度变为10。

3、在数组存满之前 List.add 中不会再调用 grow() 扩容方法了。

4、当第十一次存入时, List.add 再次调用 grow() 扩容方法。

      数组长度会变为原数组长度的1.5倍。

5、扩容不是在老数组基础上拼接的,而是创建了一个1.5倍长度的新数组。

      并把老数组的元素复制到新数组。

 面试时参考话术

ArrayList底层数据结构是数组,当创建ArrayList对象时,底层初始化了一个空数组,数组是Object类型,数组名是elementData。

        当第一次添加元素时,数组长度扩容为10。

        ……

        当第11次添加时,会触发扩容机制,其实就是调用 grow方法,扩容为原数组长度的1.5倍。

        每次扩容时,都是创建一个新数组,将老数组的元素通过 Arrays工具类复制到新数组中。elementData 指向了新数组。

ArrayList和 LinkedList 区别?

ArrayList 底层数据结构 数组。

LinkedList 底层数据结构 链表。

功能上区别:

        ArrayList  查询快,增删慢。

        原因:顺序存储,有索引,可以根据索引,直接定位到元素,所以查询快由于是顺序存储,新增或者删除,都会对后续的元素有影响。

        LinkedList  查询慢,增删快。

        原因:不是顺序存储,每个结点相连,一个结点中可以存储下一个和上一个结点,这样的话,增删元素,只对相邻的结点有影响,其他结点不受影响;由于没有下标,所以,查询元素时,需要(从头结点或尾结点)遍历。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值