• 集合_Collection_ArrayList扩容机制


    总结:
    01.ArrayList中维护了一个Object类型的数组elementData(transient Object[] elementData)
    02.创建ArrayList对象时 若使用的是无参构造器 则elementData容量为0 第一次添加元素时扩容为10 若再次扩容 则扩容为当前容量的1.5倍
    03.创建ArrayList对象时 若使用的是有参构造器 则elementData容量为参数指定容量 扩容时扩容为当前容量的1.5倍(注:存在0-1、1-2的情况)
    
    不可认为 new ArrayList<>() 与 new ArrayList<>(0) 等价 文章末尾处将图解说明
    
    关于修饰elementData数组的transient关键字:被transient关键字修饰的对象不会被序列化
    关于扩容后的数组:扩容实际上调用了Arrays.copyOf(elementData, newCapacity)方法 返回了一个新数组

    无参构造

    1. public ArrayList() {
    2. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    3. }

    有参构造

    1. public ArrayList(int initialCapacity) {
    2. if (initialCapacity > 0) {
    3. this.elementData = new Object[initialCapacity];
    4. } else if (initialCapacity == 0) {
    5. this.elementData = EMPTY_ELEMENTDATA;
    6. } else {
    7. throw new IllegalArgumentException("Illegal Capacity: "+
    8. initialCapacity);
    9. }
    10. }
    1. public ArrayList(Collection c) {
    2. Object[] a = c.toArray();
    3. if ((size = a.length) != 0) {
    4. if (c.getClass() == ArrayList.class) {
    5. elementData = a;
    6. } else {
    7. elementData = Arrays.copyOf(a, size, Object[].class);
    8. }
    9. } else {
    10. // replace with empty array.
    11. elementData = EMPTY_ELEMENTDATA;
    12. }
    13. }

    一些属性

    1. transient Object[] elementData;
    2. private static final Object[] EMPTY_ELEMENTDATA = {};
    3. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    扩容机制解读(以add方法为例):

            进入add方法后,将先调用ensureCapacityInternal方法以判断是否需要扩容,若需要则进行扩容,反之则不进行扩容,之后再向elementData数组中添加元素(即向集合中添加元素时,均会检测是否需要进行扩容);参数size + 1将作为minCapacity传入,即集合的最小容量需求

    注:size指集合中存放的元素个数

    1. public boolean add(E e) {
    2. ensureCapacityInternal(size + 1); // Increments modCount!!
    3. elementData[size++] = e;
    4. return true;
    5. }

            进入ensureCapacityInternal方法,将调用ensureExplicitCapacity方法,该方法为判断是否需要进行扩容,并真正调用扩容方法的方法,但传入的参数需要先经过calculateCapacity方法处理

    1. private void ensureCapacityInternal(int minCapacity) {
    2. ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    3. }

            进入calculateCapacity方法,若elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,即集合是通过无参构造创建的, 将minCapacity修改为DEFAULT_CAPACITY,即minCapacity = 10;否则返回传入的minCapacity,不做修改

    注:该方法决定了,集合若为无参构造创建,则第一次扩容将被扩容为10

    1. private static int calculateCapacity(Object[] elementData, int minCapacity) {
    2. if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    3. return Math.max(DEFAULT_CAPACITY, minCapacity);
    4. }
    5. return minCapacity;
    6. }
    7. private static final int DEFAULT_CAPACITY = 10;

            进入ensureExplicitCapacity方法,若minCapacity - elementData.length > 0,即集合的最小容量需求大于elementData数组的容量,将调用grow方法进行扩容,否则不进行扩容

    注:modCount用于记录集合元素的被修改次数,在许多方法中均被调用

    1. private void ensureExplicitCapacity(int minCapacity) {
    2. modCount++;
    3. // overflow-conscious code
    4. if (minCapacity - elementData.length > 0)
    5. grow(minCapacity);
    6. }

            进入grow方法,在进行一些简单判断后,调用Arrays.copyOf方法进行扩容;Arrays.copyOf方法将返回一个新的数组,即扩容后的数组实际上和扩容前的数组不是同一个数组,但Arrays.copyOf方法会保留扩容前的数组中的元素,并在扩容的部分填入null

    注:oldCapacity + (oldCapacity >> 1)即为oldCapacity + oldCapacity/2,该代码决定了大部分的扩容,扩容后的数组容量为扩容前的1.5倍(存在0-10、0-1、1-2的特殊情况)

    1. private void grow(int minCapacity) {
    2. // overflow-conscious code
    3. int oldCapacity = elementData.length;
    4. int newCapacity = oldCapacity + (oldCapacity >> 1);
    5. if (newCapacity - minCapacity < 0)
    6. newCapacity = minCapacity;
    7. if (newCapacity - MAX_ARRAY_SIZE > 0)
    8. newCapacity = hugeCapacity(minCapacity);
    9. // minCapacity is usually close to size, so this is a win:
    10. elementData = Arrays.copyOf(elementData, newCapacity);
    11. }

    注意事项:

     不可认为 new ArrayList<>() 与 new ArrayList<>(0) 等价

    前者:很显然,扩容后elementData数组容量为10

    后者:很显然,扩容后elementData数组容量为1

  • 相关阅读:
    你知道怎么改善Java代码吗?
    Hadoop编程——第一章:大数据概念
    [LeetCode84双周赛] [模拟] 6174. 任务调度器 II,[贪心&数学] 6144. 将数组排序的最少替换次数
    linux之perf(2)list事件
    MySQL--执行一条 select 语句,期间发生了什么?
    华为云云耀云服务器L实例评测|服务器实例基础使用实践
    基于三平面映射的地形纹理化【Triplanar Mapping】
    python过滤非法字符
    设计模式—设计模式总览
    OpenHarmony 系统能力 SystemCapability 使用指南
  • 原文地址:https://blog.csdn.net/Mudrock__/article/details/126867363