ArrayList扩容源码剖析

ArrayList扩容源码剖析,第1张

ArrayList扩容源码剖析 一、先看ArrayList的简单总结

1、ArrayList中维护了一个Object类型的数组elementData.

     transient Object[] elementData;(Object类型的数组说明什么类型都可以放)

     对象在序列化的时候,transient修饰的属性不会被序列化

2、当创建对象时,如果使用的是无参构造器,则初始elementData容量为0,其实就是一个空数组

3、当添加元素时:先判断是否需要扩容,如果需要扩容,则调用grow方法,否则直接添加元素到合适位置

4、当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。

5、如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity

6、如果使用的是指定容量capacity的构造器,如果需要扩容,则直接扩容elementData为1.5倍。


二、底层源码解析1
 1、我们使用下面的代码程序进行源码debug分析
package com.kgf.kgfjavalearning2021.collection;

import java.util.ArrayList;

public class ArrayListSource {

    public static void main(String[] args) {

        //使用无参构造创建ArrayList对象
        ArrayList arrayList = new ArrayList();
        //使用for循环为list添加1-10数据
        for (int i = 0; i < 10; i++) {
            arrayList.add(i);
        }
        //使用for循环为list添加11-15数据
        for (int i = 11; i <= 15; i++) {
            arrayList.add(i);
        }
        arrayList.add(100);
        arrayList.add(200);
        arrayList.add(null);
    }
}
2、首先进行下面创建无参构造器的源码分析

进入内部源码查看:

 3、当第一次向ArrayList集合中添加元素时

 点击进入add方法:

下面我们进入ensureCapacityInternal方法,这个方法是用来确认底层数组大小是否够用来存放数据,如果不够就需要进行扩容:

 可以发现上面会进行判断数组是不是一个空数组,因为第一次无参构造创建ArrayList集合底层就是一个空数组,所以如果发现是一个空数组,那么扩容elementData大小为10

 下面还需要进入ensureExplicitCapacity方法去判断是否需要真的扩容:

 上面的含义就是ArrayList是空间不够了才扩容的,假设现在插入第11个元素,但是只有10个空间,就触发grow扩容

4、下面分析grow扩容方法

上面的代码逻辑分析:

1)、首先获取elementData数组的长度oldCapacity

2)、oldCapacity >> 1表示就是oldCapacity除以2,所以newCapacity就等于oldCapacity
       的1.5倍

3)、但是第一次的时候oldCapacity等于0,所以不会走这个1.5倍的扩容机制

 4)、判断newCapacity是否大于MAX_ARRAY_SIZE,如果大于走hugeCapacity方法

 下面进入hugeCapacity方法看看:

可以发现最大就是Integer.MAX_VALUE 

 5)、最后就是真正的开始扩容了

 

 并且注意:Arrays.copyOf这个方法在扩容的时候会保留原来的数据,例如:

String[] arra = ["1","2"];

使用Arrays.copyOf扩容到5个,结果如下:

 String[] arra = ["1","2",null,null,null];

5、最后回到add方法进行添加元素,因为此时经过扩容,大小已经够了

注意,注意,注意,Idea 默认情况下,Debug 显示的数据是简化后的(就是看不到全部数据),如果希望看到完整的数据需要做以下设置.


三、底层源码解析2
1、下面我们把上面的测试代码程序设置一个初始化集合大小
package com.kgf.kgfjavalearning2021.collection;

import java.util.ArrayList;

public class ArrayListSource {

    public static void main(String[] args) {

        //使用无参构造创建ArrayList对象
        ArrayList arrayList = new ArrayList(8);
        //使用for循环为list添加1-10数据
        for (int i = 1; i < 11; i++) {
            arrayList.add(i);
        }
        //使用for循环为list添加11-15数据
        for (int i = 11; i <= 15; i++) {
            arrayList.add(i);
        }
        arrayList.add(100);
        arrayList.add(200);
        arrayList.add(null);
    }
}

 2、下面我们进行debug查看源码

 创建ArrayList对象完成,我们看一下第一次添加元素时流程:

 

 下面我们看一下当添加的元素超过8个的时候扩容方式:

 

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5683143.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存