集合之ArrayList的底层扩容机制源码分析(详细理解)

集合之ArrayList的底层扩容机制源码分析(详细理解)
1.在进入源码前需要了解到的结论

(1)ArrayList中维护了一个Object类型的数组elementData(transient Object[]Data),其中的transient修饰符表示该属性不能被序列化。
(2)当创建ArrayList对象时,使用的是无参构造,则初始elementData容量为0,第一次加入数据元素后,则扩容element容量为 10,如果需要再次扩容,则扩容elementData容量的1.5倍
(3)如果使用的是指定大小的构造器,则elementData的容量为指定大小,如果需要扩容则直接扩容原来容量的1.5倍。

========开始进入源码分析=
先来一段测试代码:
package com.heyuanhang.conllention_;

import java.util.ArrayList;

/**

  • @Author HeYuanHang
  • @Date: 2021/4/17 12:57
  • @Version 1.8
    */
    public class ArrayListYuanMa {
    public static void main(String[] args){
    //无参构造器,定义一个ArrayList对象时,会初始化一个空数组
    //当第一次加入数据元素时会申请一个10个长度的数组
    ArrayList list=new ArrayList();
    list.add(“heyuanhang”);
    }
    }
    1.首先ArrayList list=new ArrayList();执行这段代码时使用的时无参构造,则底层维护的elementData的容量为0.(由源码可知)
    public ArrayList() {
    //指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    //DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组的定义如下所示
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    2.执行list.add(“heyuanhang”);这段代码时,会先判断一下添加这个数据元素后是否超出elementData的容量,如果超出了就需要进行扩容,但是再进行扩容之前会有一个判断的环节,就是判断是先给10个容量(使用无参构造且第一次添加数据时)还是给原本容量的1.5倍(看下源码)
    public boolean add(E e) {
    //先判断添加一个元素是否超出了之前的容量,当然第一次时这儿的elementData容量为0,肯定超出,然后进入 ensureCapacityInternal方法
    ensureCapacityInternal(size + 1); // Increments modCount!!
    elementData[size++] = e;
    return true;
    }

//看一下 ensureCapacityInternal()方法
//int minCapacit这个形参就是elementData数组添加一个1元素后的长度
private void ensureCapacityInternal(int minCapacity) {
//如果elementData是一个{}空数组,则就开始申请10个大小的空间
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//DEFAULT_CAPACITY这个值就是10,minCapacity=1
//然后通过Math的max方法取二者的最大值,赋值给minCapacity
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}//其实这个if语句就是判断elementData是否为空的
//然后进入ensureExplicitCapacity方法
ensureExplicitCapacity(minCapacity);
}
//ensureExplicitCapacity方法
//int minCapacity这个形参就是elementData数组添加一个1元素后的长度,如果是经过ensureCapacityInternal方法的if语句后就是10
//当然这儿的值是10
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//这个值就是记录数组被修改的次数

    // overflow-conscious code
//如果minCapacity比elementData数组的长度大
//这而才真正的开始扩容
    if (minCapacity - elementData.length > 0)
        //这个方法才是真正的扩容方法
        grow(minCapacity);
}

//看一下grow方法
//int minCapacity这个形参就是elementData数组添加一个1元素后的长度,如果是经过ensureCapacityInternal方法的if语句后就是10
private void grow(int minCapacity) {
// overflow-conscious code
//先把elementData的长度赋值给oldCapacity
int oldCapacity = elementData.length;//测试代码中这儿就是0
//再将oldCapacity与其向右位移1运算的值的和赋值给 newCapacity
//oldCapacity >> 1等价与oldCapacity/2
int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容1.5倍就是这儿体现出来的
//如果newCapacity比minCapacity小的话
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);
}
因此综上所述:ArrayList的底层扩容机制有以下步骤:

1.先判断加入一个元素后是否超过原来的数组容量也就是elementData的容量
2.然后会进入ensureCapacityInternal这个方法开始判断以下刚开始时elementData是否是一个空数组
如果是的话就会将数组的长度标注为10
3.然后会进入ensureExplicitCapacity(int minCapacity)方法,当然再进行真正扩容的时候还会判断一下是否需要进行1.5倍扩容,然后才是调用grow(int minCapacity)进行真正的扩容

A.这儿需要补充一下:
ensureCapacityInternal(size + 1); 该方法的size可以理解成一个跟踪指针,它的值标值ArrayList中有多少个元素了。也就是已经存在多少个元素了。
B.顺便复习一下ArrayList的常用方法
(1)add(Object object):添加元素
(2)add(int index ,Object obj):向指定的index位置开始插入obj
(3)addAll(int dex,Collection):向指定位置dex开始插入一个集合元素
(4)get(int dex):获取指定位置dex处的元素
(5)indexOf(Object obj):返回obj在集合中的首次出现的位置
(6)lastIndexOf(Object obj):返回obj在集合中最后一次出现的位置
(7)remove(int dex):删除指定位置dex处的元素
(8)Object set(int dex,Object obj):将指定位置dex处的元素替换成obj
(9)subList(int st,int end):返回从st到end的子集合。包括st小于end

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值