ArrayList的自动扩容机制

作者: landy8530 | 来源:发表于2017-08-24 17:09 被阅读438次

    今天看到一个面试题如下:
    ArrayList list = new ArrayList(20);中的list扩充几次()
    A 0 B 1 C 2 D 3

    1.面试题

    一开始自以为是的认为是2,默认容量是10,以为是要扩容两次。后面仔细研读ArrayList的源码后发现,其实并不是2次。
    ArrayList的默认初始容量为10,当然也可以自定义指定初始容量,随着动态的向其中添加元素,其容量可能会动态的增加,那么扩容的公式为:
    新容量 = 旧容量/2 + 旧容量
    比如:初始容量为4,其容量的每次扩充后的新容量为:4->7->11->17->26->...
    即每次扩充至原有基础的1.5倍
    扩容方法如下图所示:

    扩容方法.png

    ArrayList的构造函数总共有三个:
    (1)ArrayList()构造一个初始容量为 10 的空列表。
    (2)ArrayList(Collection<? extends E> c)构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
    (3)ArrayList(int initialCapacity)构造一个具有指定初始容量的空列表。
    调用的是第三个构造函数,直接初始化为大小为20的list,没有扩容,所以选择A

    2.进阶

    假设有以下程序:

    ArrayList<Integer> arrayList = new ArrayList<Integer>(20);
    for(int i=0;i<50;i++) {
         arrayList.add(i);
    }
    
    

    初始化容量为20,总共有50个元素,需要扩容几次?
    下面通过debug这个小程序砍下他的执行过程。找到源码中的grow方法进行设定断点:

    image.png

    执行debug后,如下图结果,前20个元素都没有执行grow方法。

    image.png

    再次执行的时候,就进入到grow方法进行扩容操作

    image.png

    扩容操作之后,新的容量为30.以此类推,后续需要再进行两次扩容操作,如下图所示:

    image.png image.png

    故扩容次数依次为:20->30->45->67

    3.延伸

    HashMap的初始大小为16,增长时,直接容量翻番,如源代码。
    ···
    void addEntry(int hash, K key, V value, int bucketIndex) {
    if ((size >= threshold) && (null != table[bucketIndex])) {
    resize(2 * table.length);//原容量2倍
    hash = (null != key) ? hash(key) : 0;
    bucketIndex = indexFor(hash, table.length);
    }

       createEntry(hash, key, value, bucketIndex);  
    

    }

    ···
    Vector的初始大小为10,如果没有指定每次增长的大小,则默认是翻倍增长

    相关文章

      网友评论

        本文标题:ArrayList的自动扩容机制

        本文链接:https://www.haomeiwen.com/subject/eipedxtx.html