ArrayList in-depth analysis of source code

1.add()

 public boolean add(E e) {
        //1.判断是否需要扩容
        //2.进行扩容
        //size+1:因为添加了一个元素所以要加1
        ensureCapacityInternal(size + 1);  // Increments modCount!!

        //对扩容完的data进行添加数据
        //size++:因为添加了一个元素所以要加1
        elementData[size++] = e;

        //前面没有问题表示添加成功返回true
        return true;
    }

    /**
     * 扩容方法
     * @param minCapacity 最小扩容大小
     */
    private void ensureCapacityInternal(int minCapacity) {
        //1.对比判断最小扩容大小,默认最小10
        //2.进行扩容
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    /**
     * 扩容判断
     * @param elementData 数据
     * @param minCapacity 最小扩容大小
     * @return 最小扩容大小
     */
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //如果当前的数据为空DEFAULTCAPACITY_EMPTY_ELEMENTDATA={},则最小扩容大小和默认最小10容量比较找出大的
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //返回最小扩容大小
        return minCapacity;
    }

    /**
     * 扩容判断
     * @param minCapacity 最小扩容大小
     */
    private void ensureExplicitCapacity(int minCapacity) {
        //修改操作数加1
        modCount++;

        // 如果需要扩容的容量>数据的长度进行扩容,否则不需进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 最终扩容方法
     * @param minCapacity 最小扩容大小
     */
    private void grow(int minCapacity) {
        // 原来的容等于数据长度
        int oldCapacity = elementData.length;
        //新容量等于原来容量*3/2,也就是原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果新容量<最小扩容大小则容量扩容为最小扩容大小也就是默认10或者size+1
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //如果新容量>最大数组容量(Integer.MAX_VALUE-8)
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            //最大容量判断
            newCapacity = hugeCapacity(minCapacity);
        //扩容完之后进行数据拷贝,把原来的数据拷贝到扩容后的数组里
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    /**
     * 扩容判断
     * @param minCapacity 最小扩容大小
     * @return 最大容量
     */
    private static int hugeCapacity(int minCapacity) {
        //如果容量已经超过int的最大限度,抛出异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //如果最小扩容大小>数组最大容量(Integer.MAX_VALUE-8)返回Integer.MAX否则等于Integer.MAX_VALUE-8
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

Summary: When adding data, it is necessary to make a judgment on capacity expansion first, and expand capacity if the capacity is not enough. The capacity is expanded to 1.5 times the original data length, the default initial capacity is 10, and the maximum capacity is Integer.MAX_VALUE.

2.addAll()

public boolean addAll(Collection<? extends E> c) {
        //转化成数组
        Object[] a = c.toArray();
        //获取数据长度
        int numNew = a.length;
        //原有的数据长度+添加的数据长度进行扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //扩容完进行数据拷贝,拷贝到扩容后的数组里
        System.arraycopy(a, 0, elementData, size, numNew);
        //现在数据长度=原有的数据长度+添加的数据长度
        size += numNew;
        //如果添加的数据长度不为0返回true,否则false
        return numNew != 0;
    }

3.get()

public E get(int index) {
        //检查是否越界
        rangeCheck(index);
        //返回下标数据
        return elementData(index);
    }

    private void rangeCheck(int index) {
        //如果查找的下标大于数据长度,抛出异常
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    

Summary: When obtaining, you need to check whether the subscript is out of bounds, and the data corresponding to the subscript is not returned.

4.remove()

   public E remove(int index) {
        //检查数组是否越界,越界抛出异常
        rangeCheck(index);
        //操作数++
        modCount++;
        //获取数据
        E oldValue = elementData(index);
        //拷贝数据的长度
        int numMoved = size - index - 1;
        //如果需要拷贝数据
        if (numMoved > 0)
            //1.目标数据elementData,2.要从哪个地方开始拷贝index+1,3.拷贝的长度numMoved,4.数据拷贝到这个对象(第3个elementData),5.目标数组的开始拷贝起始位置index
            System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);
        //把最后的数据置空,并长度减1
        elementData[--size] = null; // clear to let GC do its work
        //返回删除的数据
        return oldValue;
    }

Remove the diagram (picture from Xiaoboge)

Summary: When deleting, judge whether the subscript is out of bounds, first copy the data, then set the last data to empty, and reduce the length by 1.

Guess you like

Origin blog.csdn.net/ysfengshu/article/details/126994445