Java基础系列之ArrayList的增加、删除、扩容

ArrayList扩容,新增,删除过程,原文出自:https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/collection/ArrayList%E6%BA%90%E7%A0%81+%E6%89%A9%E5%AE%B9%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90.md
   特别说明:   

System.arraycopy(elementData, index+1, elementData, index, numMoved);   
// 将elementData中从index+1开始的元素,复制到elementData中从index位置开始的数组里

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
其中:
Object src : 原数组   
int srcPos : 从原数组copy的起点
Object dest : 目标数组
int destPos : paste到目标数组的起点
int length  : 要copy的数组的长度


扩容: 操作:

   /**
     * 将指定的元素追加到此列表的末尾。
     */
    public boolean add(E e) {
        //添加元素之前,先调用ensureCapacityInternal方法
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //这里看到ArrayList添加元素的实质就相当于为数组赋值
        elementData[size++] = e;
        return true;
    }
 //得到最小扩容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
              // 获取默认的容量和传入参数的较大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    } // 当 要 add 进第 1 个元素时,minCapacity 为 1,在 Math.max()方法比较后,minCapacity 为 10。
//判断是否需要扩容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            //调用grow方法进行扩容,调用此方法代表已经开始扩容了
            grow(minCapacity);
    }
   /**
     * 要分配的最大数组大小
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * ArrayList扩容的核心方法。
     */
    private void grow(int minCapacity) {
        // oldCapacity为旧容量,newCapacity为新容量
        int oldCapacity = elementData.length;
        //将oldCapacity 右移一位,其效果相当于oldCapacity /2,
        //我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
       // 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,
       //如果minCapacity大于最大容量,则新容量则为`Integer.MAX_VALUE`,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。
        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);
    }

    当 add 第 1 个元素时,oldCapacity 为 0,经比较后第一个 if 判断成立,newCapacity = minCapacity(为 10)。但是第二个 if 判断不会成立,即 newCapacity 不比 MAX_ARRAY_SIZE 大,则不会进入 hugeCapacity 方法。数组容量为 10,add 方法中 return true,size 增为 1。

    当 add 第 11 个元素进入 grow 方法时,newCapacity 为 15,比 minCapacity(为 11)大,第一个 if 判断不成立。新容量没有大于数组最大 size,不会进入 hugeCapacity 方法。数组容量扩为 15,add 方法中 return true,size 增为 11。
    以此类推······


新增:在第index个位置插入,假设未超过数组容量:内部操作为

     /** 在此列表中的指定位置插入指定的元素。
     ** 先调用 rangeCheckForAdd 对index进行界限检查;然后调用 ensureCapacityInternal 方法保证capacity足够大;                                          
     ** 再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1。    
     **/    
    public void add(int index, E element) {          
        rangeCheckForAdd(index);          
        ensureCapacityInternal(size + 1);  // Increments modCount!!          
        // arraycopy()这个实现数组之间复制的方法一定要看一下,下面就用到了arraycopy()方法实现数组自己复制自己
        // System.arraycopy(elementData, index, elementData, index + 1, size - index);
        // 从index位置开始的元素拷贝到index+1位置开始元素,意思是所有元素从index位置开始后移一位
           elementData[index] = element;   
        // 空出来的index位置插入新元素element       
           size++;    
     }

删除:删除第index个位置的元素

操作:  

/*** 删除该列表中指定位置的元素。 将任何后续元素移动到左侧(从其索引中减去一个元素)。               
     * */    
    public E remove(int index) {        
         rangeCheck(index);       
         modCount++;       
         E oldValue = elementData(index);       
         int numMoved = size - index - 1;  //numMoved :需要移动的元素个数, 因为index是从0开始的,所以要减1 
          if (numMoved > 0)  // 将数组从index+1位置开始的元素拷贝到数组从index开始的位置,简言之就是index+1位置开始的元素统一前移 
               System.arraycopy(elementData, index+1, elementData, index,numMoved);       
               elementData[--size] = null; // clear to let GC do its work      
               // 从列表中删除的元素        
               return oldValue;   
    }

 

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页