美文网首页
Java源码阅读系列(一)-ArrayList源码阅读

Java源码阅读系列(一)-ArrayList源码阅读

作者: boyang的博客 | 来源:发表于2020-10-27 13:29 被阅读0次

    ArrayList源码分析

    1、增加元素

    ArrayList有两个不同的add()方法。常用的就是第一个,添加元素到list的末尾,只分析第一个方法。

    /**
         * 将指定的元素添加到列表末尾.
         *
         * @param e element to be appended to this list
         * @return <tt>true</tt> (as specified by {@link Collection#add})
         */
        public boolean add(E e) {
            //确认List容量
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            //把元素放到List的末尾
            elementData[size++] = e;
            return true;
        }
    

    来看ensureCapacityInternal(size + 1); // Increments modCount!!

    执行的是以下方法,size是当前ArrayList的大小0:

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));  //calculateCapacity执行的是下面的静态方法calculateCapacity
    }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    } 
    

    calculateCapacity方法中对elementData进行检查,如果它是DEFAULTCAPACITY_EMPTY_ELEMENTDATA的,就返回size和DEFAULT_CAPACITY两者中的最大值,第一次添加元素时,扩容到默认值10。

    调用无参构造的时候,把DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给了 elementData,此时一定是它。

    /**
    * Constructs an empty list with an initial capacity of ten.
    */
    public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    

    DEFAULT_CAPACITY默认为10.

    /**
    * Default initial capacity.
    */
    private static final int DEFAULT_CAPACITY = 10;
    

    源码中对elementData的注释写的很清楚,如果 一个ArrayListelementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA,那么在第一次添加元素时就扩容为默认容量10.

        /**
         * The array buffer into which the elements of the ArrayList are stored.
         * The capacity of the ArrayList is the length of this array buffer. Any
         * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
         * will be expanded to DEFAULT_CAPACITY when the first element is added.
         */
        transient Object[] elementData; // non-private to simplify nested class access
    

    下面这一步就是很重要的扩容了,calculateCapacity返回ArrayList的大小之后,执行ensureExplicitCapacitymodCount++,然后判断元素的lengthminCapacity的大小,在第一次增加元素的时候,会进入grow

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

    扩充:

    /**
         * Increases the capacity to ensure that it can hold at least the
         * number of elements specified by the minimum capacity argument.
         *
         * @param minCapacity the desired minimum capacity
         */
    private void grow(int minCapacity) {
        // 获取当前数组容量
        int oldCapacity = elementData.length;
        //扩容,新数组容量 = 当前数组容量 + 当前数组容量/2
        //右移除以2的几次幂,左移乘以2的几次幂
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果扩充之后的容量还小于想要的容量,扩充容量就等于想要的容量
        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);
    }
    

    大容量分配:

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //判断想要的是否大于临界值,如果大于,则返回Integer.MAX_VALUE(0x7fffffff),否则返回MAX_ARRAY_SIZE
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }
    

    MAX_ARRAY_SIZE为什么要-8

    因为某些VM会在数组中保留一些头字,尝试分配这个最大存储容量,可能会导致Array容量大于VMlimit,最终导致OutOfMemoryError

    /**
         * The maximum size of array to allocate.
         * Some VMs reserve some header words in an array.
         * Attempts to allocate larger arrays may result in
         * OutOfMemoryError: Requested array size exceeds VM limit
         */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    

    然后增加的过程就完事了。

    未完待续。。。
    很快!

    相关文章

      网友评论

          本文标题:Java源码阅读系列(一)-ArrayList源码阅读

          本文链接:https://www.haomeiwen.com/subject/zofxvktx.html