Java ArrayList源码分析,基于Java 11

ArrayList源码分析

源码分析


private int size; //ArrayList中元素的个数


transient Object[] elementData; //用该数组来存储ArrayList中的元素


private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//默认的ArrayList中元素的最大个数


private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//新建ArrayList的时候若没有指定ArrayList的初始大小,则默认是一个空的数组,直到往ArrayList中添加了元素则不为空


private static final int DEFAULT_CAPACITY = 10; //新建ArrayList对象的时候,若没有指定List的容量,则默认为10

/**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
public void add(int index, E element) {
    rangeCheckForAdd(index);//检查插入的index是否合法,index的位置范围为[0, size]
    modCount++;
    final int s;
    Object[] elementData;//新建一个临时数组
    //elementData = this.elementData将原来的数组赋值给现在新建立的数组
    //(elementData = this.elementData).length,求出elementData的长度
    //size:List中包含的元素个数,而不是值List的容量大小。
    
    //如果List中的元素的个数等于其实际容量的大小,说明该进行扩容了,不然无法容纳新插入的元素
    if ((s = size) == (elementData = this.elementData).length)
        elementData = grow();//grow方法用于扩大elementData[]的容量大小
    //src:源数组,srcPos:源数组拷贝的起点位置,dest:目地数组,destPos:目的数组接受拷贝值的起点位置,length:拷贝的长度
    //arraycopy(Object src, int  srcPos, Object dest, int destPos, int length)
    //从elementData的index位置拷贝s - index个元素到elementData的index + 1的位置
    System.arraycopy(elementData, index,
                     elementData, index + 1,
                     s - index);
    //插入元素element到index这个位置
    elementData[index] = element;
    //更新size的大小
    size = s + 1;
}

private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//扩大elementData[]的容量大小
private Object[] grow() {
    //让elementData[]的容量增加。注意,这里写的虽然是size + 1,新的数组的容量可能不止加1。实际上是新建了一个数组,再将原来的数组中的元素拷贝到新的元素中。
    return grow(size + 1);
}

private Object[] grow(int minCapacity) {
    //Arrays.copyOf(T[] original, int newLength)
    //将原来的数组original拷贝到一个新的数组,并使得新数组的长度为newLength
    return elementData = Arrays.copyOf(elementData,
                                       newCapacity(minCapacity));
}

/**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by 50% if that suffices.
     * Will not return a capacity greater than MAX_ARRAY_SIZE unless
     * the given minimum capacity is greater than MAX_ARRAY_SIZE.
     *
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
//该方法用来在扩容时指明应该扩容到多大
//返回List的应该扩容到多大。
//返回的容量大小至少应该和给定的最小容量一样大。如果内存空间足够的话,会使得容量相比原来的扩容50%
//除非调用这个程序时指定要扩容的容量 > MAX_ARRAY_SIZE(默认的最大容量),否则不会返回一个大于MAX_ARRAY_SIZE的数

//minCapacity用来指明扩容后的容量最小应该是多大,但是实际扩容后的容量大小并不一定等于minCapacity,得分情况讨论
private int newCapacity(int minCapacity) {
    // overflow-conscious code
    //扩容前elementData的容量,ArrayList中的元素实际上还是存储在数组中的
    int oldCapacity = elementData.length;

    //新的容量 = 以前的容量 + 以前的容量 / 2 ; 相当于就是把容量扩大了一半,新的容量是原来的容量的1.5倍
    //默认情况下应该是扩容1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);//oldCapacity >> 1相当于是oldCapacity / 2
    
    //为什么会出现newCapacity - minCapacity <= 0的情况
    //扩容的目的是让List的容量变大,出现newCapacity - minCapacity <= 0的原因有:
    //1.如果List原来是一个空的List,其容量为0,根据这个空的List计算而得到的newCapacity自然也是0,那么指定的minCapacity很大可能会大于newCapacity
    //2.如果指定的minCapacity < 0,那么可能是因为Java的虚拟机的容量不够了,无法再分配容量给该数组了,也就是说无法为List扩容了。
    //  所以设置为一个小于0的数,用来抛出一个OOM异常。什么时候可能会抛出OOM异常呢?见解释: Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.
    //3.排除前面两种情况,说明指定的minCapacity要大于程序默认扩容的容量(newCapacity),那这种情况,就以指定的minCapacity作为List扩容后的容量大小.
    if (newCapacity - minCapacity <= 0) {
        //elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA说明该List是一个空的List,一个空的List一旦被放入了元素,若未指定初始容量的大小,则会自动为其扩容到默认的初始容量DEFAULT_CAPACITY(10)
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        //如果minCapacity < 0,则会抛出OutOfMemoryError异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return minCapacity;
    }
    //程序能走到这里,则说明用户指定的minCapacity < 程序默认扩容的容量(newCapacity),那么就以newCapacity作为List扩容后的容量大小
    //如果扩容后的容量newCapacity大于MAX_ARRAY_SIZE(List的最大容量),则返回一个最大容量,若newCapacity不大于MAX_ARRAY_SIZE,则直接返回当前newCapatity
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        : hugeCapacity(minCapacity);
}


private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE)
        ? Integer.MAX_VALUE
        : MAX_ARRAY_SIZE;
}

扩容图式

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值