Java中ArrayList中扩容机制的底层原理分析

ArrayList集合

1. 方法

public class ArrayList<E> extends AbstractList<E>
        implements List<E>

ArrayList继承了Collection类,且接口为List,所以父类和接口中的方法都可以使用

2. 底层原理

ArrayList底层是数组结构的

结论

  • 利用空参创建的集合,在底层创建了一个默认长度为0的数组
  • 添加第一个元素时,底层会将数组的长度扩充为一个新的长度——10
  • 存满时,会扩容1.5倍
  • 如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

2.1 空参构造

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  }
    //跳转到elementData
    transient Object[] elementData;
    //再跳转到DEFAULTCAPACITY_EMPTY_ELEMENTDATA中
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  • 从空参构造的底层代码可以看出ArrayList为数组,而elementData为数组的名称,而其长度为0,(DEFAULTCAPACITY_EMPTY_ELEMENTDATA 长度为0)

2.2 扩容的底层原理

    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
  }
        private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

The size of the ArrayList (the number of elements it contains).
@serial

size:数组列表的大小(它包含的元素数)

  1. 第一次中调用add(E e)时,系统会再调用另一种的add(e, elementData,size)进行数据添加,其中e为我们要储存的元素,elementData为我们在调用空参构造时,系统自动构造的空数组,size为数组中的元素个数和集合的长度(不等同element.length,即数组长度)
  2. 分析第二次add方法,当s == elementData.lengt时,elementData = grow()进行跳转;第四步中elementData.length增大到10,即s不等于elementData.length,elementData[ ] = e 进行数据存储,并且size也相应+1,当存储了10个元素时(即size == 10),s == elementData时,加入grow()方法,直接跳转到第五步
    //这里跳转到了grow()方法
    private Object[] grow() {
        return grow(size + 1);
    }
  1. grow()方法中又调用了一次grow()方法,而传入实参为 size + 1
    //再次跳转到grow()
    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }
private static final int DEFAULT_CAPACITY = 10;
  • 在grow(int minCapacity)中,minCapacity = size + 1
  • 第二行中,变量oldCapacity储存原来的elementData数组的长度
  1. 第一次时,oldCapacity = 0,minCapacity = 1,且elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA,所以不符合if判断,进入else中,DEFAULT_CAPACITY > minCapacity,则elementData的长度增大到10,这时再返回第二步中进行数据储存
  2. 当size == 10时,minCapacity == 11,oldCapacity = 10,符合if()判断,调用ArraysSupport.newLength(int oldLength, int minGrowth, int prefGrowth)方法,其中int oldLength的实参为oldCapacityint minGrowth的实参为minCapacity - oldCapacity,int prefGrowth的实参为oldCapacity >> 1(等同于oldCapacity/2)
    public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // preconditions not checked because of inlining
        // assert oldLength >= 0
        // assert minGrowth > 0

        int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
        if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
            return prefLength;
        } else {
            // put code cold in a separate method
            return hugeLength(oldLength, minGrowth);
        }
    }
   public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;//2147483639
   @Native public static final int   MAX_VALUE = 0x7fffffff;//2147483647
  1. oldLength = 10,minGrowth =1,prefGrowth = 5. 则prefLength = 15,进行if判断,return preLength == 15,则在第五步中 newCapacity = preLength = 15,然后return elementData,这里又调用了Arrays.copyOf(T[] original,int newLength)方法,T[] original的实参为 elementData, int newLength的实参为 newCapacity
    public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
        }
        public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
  1. 用copyof()方法进行复制,创建一个长度为newCapacity = 15的新数组,并把elementData的数据复制到新数组,在把新数组赋值给elementData。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aweken dream

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值