ArrayList的删除实现

      ArrayList的删除实现其实就是和数组添加相反的一个过程,只不过删一个元素和删除多个元素的实现方式略有区别,但是思路还是一样,如下图:

 

一、remove方法

如上,移除一个元素时,可以通过元素或者元素的索引移除,有四个步骤:

(1)判断索引index是否越界

(2)将 index + 1 及之后的元素向前移动一位

(3)最后一个值变为null

(4)长度size - 1

将该索引以后的元素下标前移,最后一个元素置为NULL,源码如下:

       public E remove(int index) {
            /*检查索引是否越界*/
            rangeCheck(index);
          /*记录集合得修改次数*/
            modCount++;
            /*获取被删除的元素*/
            E oldValue = elementData(index);
            /*移动的元素个数*/
            int numMoved = size - index - 1;
            if (numMoved > 0)
                /*参数:被复制的数组, 从被复制数组的第几个元素开始复制,粘贴的目标数组,从目标数组第几个元素开始粘贴,复制的元素个数*/
                System.arraycopy(elementData, index+1, elementData, index, numMoved);
             
            /*将最后一个元素置空,然后GC机制会回收该内存,并且ArrayList的长度-1*/
            elementData[--size] = null; 

            return oldValue;
        }
    public boolean remove(Object o) {
        /*如果删除的元素对象为null*/
        if (o == null) {
            /*删除ArrayList中第一个为null的元素*/
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            /*删除ArrayList中匹配到的第一个元素*/
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    /*不进行索引验证,直接删除*/
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }

二、removeAll方法

removeAll的实现方式虽然在思路上和前面一致,但是代码实现略有不同,在移除多个元素时,会遍历数组,先去将数组中的每个元素一一和移除元素数组里的元素匹配,

如图:

当移除完成后,会将最后几位(和移除元素数组长度相同)的元素置为null,源码如下:

    public boolean removeAll(Collection<?> c) {
        /*验证删除Collection是否为null,若null则抛出NullPointerException*/
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
    
    private boolean batchRemove(Collection<?> c, boolean complement) {
        /*获取原数组*/
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            /*遍历所有元素,如果匹配到需要移除的元素,则移除该元素,并将后面未匹配到前移到移除元素位置*/
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            /*r != size 说明元素未完全匹配完,则将未匹配的size - r个元素粘贴到w以后的位置*/
            if (r != size) {
                System.arraycopy(elementData, r, elementData, w, size - r);            
                w += size - r;
            }
            if (w != size) {
                /*将移除完成w以后的元素置为null,由GC回收内存*/
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                /*数组长度置为w*/
                size = w;
                modified = true;
            }
        }
        return modified;
    }

三、clear方法

clear方法也是ArrayList的删除方法之一,只不过是清除所有元素,所以只要将所有元素置为null,由GC回收内存即可

    public void clear() {
        /*记录集合得修改次数*/
        modCount++;
        /*将每个元素置空,之后,内存会被GC回收*/
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        /*元素个数置为0*/
        size = 0;
    }

 上面删除操作,我们发现,元素是没了,但是数组的长度并没有变,那么ArrayList有没有自动缩容机制了,答案是没有,但是它提供可以实现缩容的方法,我们可以手动去触发:

/** 将数组容量缩小至元素数量 */
public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}
原文地址:https://www.cnblogs.com/zhexuejun/p/11170895.html