ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Arraylist的扩容机制

2021-06-06 20:35:19  阅读:160  来源: 互联网

标签:扩容 minCapacity elementData Arraylist 元素 添加 数组 机制 arraylist


各位看官,今天的砖好烫,先点个赞呗,微信搜索「小大白日志」关注这个搬砖人。

本文在公众号文章已同步,还有各种一线大厂面试原题、我的学习系列笔记。

arraylist每次添加元素时都会检查是否需要扩容:arraylist第一次添加元素时,赋予arraylist默认容量10,再往里面添加元素(所以arraylist默认容量10并不是初始化的时候赋予的,而是无参构造第一次添加元素的时候赋予的);以后每次添加元素前先检查当前元素个数是否已经达到容量上限,若是则先以1.5倍*原容量上限进行扩容再添加元素,如下:

  • arraylist中的初始变量
//当首次创建arraylist是无参构造,即没有指定初始容量时,赋予该默认数组给arraylist
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//当首次创建arraylist是有参构造,即指定了初始容量,但初始容量指定为0时,赋予该默认数组给arraylist
private static final Object[] EMPTY_ELEMENTDATA = {};
//用于arraylist中实际存放元素的数组,注意此变量是transient修饰的,不参与序列化
transient Object[] elementData;
//数组元素的实际个数,默认0;不同于elementData.length,elementData.length是数组长度
private int size;
  • arraylist的三个构造函数
(1)默认无参构造:
public ArrayList() {
	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
(2)指定了长度的有参构造
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];//指定长度>0,直接赋予指定长度的数组
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;//指定长度为0,赋予默认的长度为0的数组
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    }
}
(3)指定了数组元素的有参构造
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
  • arraylist添加元素,两种方法
//把元素添加到数组尾部
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 检查是否需要扩容,size为当前实际元素个数,size+1为添加元素后需要的实际最小空间;第一次添加元素时size为0,传入1
    elementData[size++] = e;//检查完再往里面添加元素
    return true;
}
//把元素添加到数组特定的下标处
public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);   // 检查是否需要扩容
    System.arraycopy(elementData, index, elementData, index + 1,size - index);//检查完先拷贝元素:把元素后移
    elementData[index] = element;//再添加元素
    size++;
}
  • 检查是否需要扩容
private void ensureCapacityInternal(int minCapacity){  
    //calculateCapacity()获取添加元素后所需的最小容量
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//获取添加元素后所需的最小数组容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //调用的无参构造初始化arraylist,且是第一次添加元素,返回10,即设置‘添加元素后所需的最小数组容量’为10:minCapacity=1,elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA,DEFAULT_CAPACITY为10
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    //其他情况:调用有参构造初始化arraylist且第一次添加元素或非第一次添加元素,则‘添加元素后所需的最小数组容量’为添加元素后实际元素个数
    return minCapacity;
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;//用于快速失败机制
    //当前数组长度=elementData.length < minCapacity='添加元素后所需的最小数组容量',则需要扩容
    //(1)无参构造第一次添加元素时:10>0,需扩容,传入10;(2)无参构造添加元素后所需的最小数组容量为11时:11>10,需扩容,传入11;...
    if (minCapacity - elementData.length > 0) 
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容1.5倍:oldCapacity>>1即oldCapacity/2=0.5*oldCapacity
    if (newCapacity - minCapacity < 0)
    //无参构造第一次添加元素时会走这一步:oldCapacity=newCapacity=0,minCapacity=10
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        //扩容后新容量newCapacity>MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8时
        newCapacity = hugeCapacity(minCapacity);
    //(1)无参构造第一次添加元素时elementData为空数组,newCapacity=10
    elementData = Arrays.copyOf(elementData, newCapacity);
}

OK,如果文章哪里有错误或不足,欢迎看官们留言。等等,看官们别走哎,请留下你们的爪印 ˇ0ˇ

标签:扩容,minCapacity,elementData,Arraylist,元素,添加,数组,机制,arraylist
来源: https://www.cnblogs.com/mofes/p/14856276.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有