zoukankan      html  css  js  c++  java
  • ArrayList add get remove 源码解析

    ArrayList 

    public class ArrayList<E> extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    add方法:

        /**
         * Appends the specified element to the end of this 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) {
            //处理动态数组的容量,不够则扩充
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    
    
        private void ensureCapacityInternal(int minCapacity) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                //容器第一次添加数据,设置容器容量大小初始值
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
            //根据给定容器大小的下限值,判断是否扩充容器
            ensureExplicitCapacity(minCapacity);
        }
    
        private void ensureExplicitCapacity(int minCapacity) {
            //fail-fast机制的基准值
            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) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            
            //每次扩充为原容器大小的1.5倍
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            
            //兜底机制,扩充后的容器大小如果还不满足条件,则使用给定的容器大小
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            
            //如果扩充后的容器大小值超出容器规定的上限,两种情况
            //1 是大小超出了int的最大值,成为负数,直接抛出异常
            //2 是大小超出了容器上限值,但是还没超出int的最大值,则容器大小初始化为int的最大值
            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();
            return (minCapacity > MAX_ARRAY_SIZE) ?
                    Integer.MAX_VALUE :
                    MAX_ARRAY_SIZE;
        }

    简而言之,就是一个可以动态扩容的数组,

    看get方法

        /**
         * Returns the element at the specified position in this list.
         *
         * @param  index index of the element to return
         * @return the element at the specified position in this list
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        public E get(int index) {
            rangeCheck(index);
    
            return elementData(index);
        }
    
        /**
         * Checks if the given index is in range.  If not, throws an appropriate
         * runtime exception.  This method does *not* check if the index is
         * negative: It is always used immediately prior to an array access,
         * which throws an ArrayIndexOutOfBoundsException if index is negative.
         */
        private void rangeCheck(int index) {
            if (index >= size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    
        // Positional Access Operations
        @SuppressWarnings("unchecked")
        E elementData(int index) {
            return (E) elementData[index];
        }

    首先检查索引是否越界,越界则抛出异常,否则返回数据。

    remove方法:

    /**
         * Removes the element at the specified position in this list.
         * Shifts any subsequent elements to the left (subtracts one from their
         * indices).
         *
         * @param index the index of the element to be removed
         * @return the element that was removed from the list
         * @throws IndexOutOfBoundsException {@inheritDoc}
         */
        public E remove(int index) {
            //检查索引是否越界
            rangeCheck(index);
    
            modCount++;
            //保留原有值,作为返回数据
            E oldValue = elementData(index);
    
            //计算需要移动的数组的数据长度
            int numMoved = size - index - 1;
            if (numMoved > 0)
                //把index后面的所有数据往前移动一位
                System.arraycopy(elementData, index+1, elementData, index,
                        numMoved);
            
            //删除数组最后一个多余的数据,便于gc回收
            elementData[--size] = null; // clear to let GC do its work
    
            return oldValue;
        }

    比较了下add和remove两者,发现add虽然有扩容机制,但是remove并没有缩容机制。随着元素的删除,只是把对应元素的引用释放,并没有把数组本身的容量大小进行调整。

  • 相关阅读:
    FFmpeg 结构体学习(八):FFMPEG中重要结构体之间的关系
    FFmpeg 结构体学习(七): AVIOContext 分析
    FFmpeg 结构体学习(六): AVCodecContext 分析
    FFmpeg 结构体学习(五): AVCodec 分析
    FFmpeg 结构体学习(四): AVFrame 分析
    FFmpeg 结构体学习(三): AVPacket 分析
    Android 通过onTouchEvent判断是否为双击事件
    FFmpeg 结构体学习(二): AVStream 分析
    Java 使用 int 数据计算百分比
    Android 关于解决MediaButton学习到的media控制流程
  • 原文地址:https://www.cnblogs.com/zhangxuezhi/p/11872248.html
Copyright © 2011-2022 走看看