ArrayList 里的 removeAll() 及 retainAll() 方法【jdk源码分析】

源码注释:仅保留此列表中包含在指定集合中的元素。换句话说,从该列表中删除指定集合中不包含的所有元素。

本人解释:原数组和参数数组做交集,保留相同的部分。

源码分析部分:

    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    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 {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.

            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

相关字段解释:

    size :原集合长度

    elementData: 原集合

    modCount : 从父类继承过来的变量,作用是记录着集合的修改次数。详情可见我另一篇博文: 请点击我   

分析部分: 主要分析 batchRemove(Collection<?> c, boolean complement)方法。 complement为true

    1、retainAll(Collection<?> c):原数组和参数数组做交集,保留相同的部分。

    2、batchRemove(Collection<?> c, boolean complement):根据 complement 的值来制定数组移除数据策略

  (1)、先分析

            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];

            这部分

            因为 complement==true。 所以,参数数组中包含原数组指定位置的数据时,就将原数组的r位置的数据覆盖掉w位置的数据,r位置的数据不变,并其w自增,r自增。      否则,r自增,w不自增

            这步处理出来的数据很重要,一定要理解到,下面举个例子:

                    原数组:     123456789   ;     参数数组:  abc358f                                                             

                    数组位置     012345678

循环次数   r   w  if值   elementData[w++]=elementData[r]    原数组值     替换位
    1          0   0  false                                                               123456789   
    2          1   0  false                                                               123456789  
    3          2   0  true      elementData[0]=elementData[2]        323456789    123456789
    4          3   1  false                                                                323456789   
    5          4   1  true      elementData[1]=elementData[4]        353456789    323456789
    6          5   2  false                                                                353456789    
    7          6   2  false                                                                353456789    
    8          7   2  true      elementData[2]=elementData[7]        358456789    353456789    
    9          8   3  false                                                                358456789       

                9   3

   这步的作用:把两个数组相同的部分前移(这步的处理尤为重要!)

(2)、再分析

                            if (w != size) {
                                // clear to let GC do its work
                                for (int i = w; i < size; i++)
                                    elementData[i] = null;
                                modCount += size - w;
                                size = w;
                                modified = true;
                            }

            这部分 

            跟着上面的例子,w==3,从原数组358456789 的 下标==3开始,将原数组大于下标3以后的数置null
            modCount 修改的次数+3,原数组的长度修改为3。

好了 到这里就分析完了,其实我觉得难以梳理的就是分析(1)。

当然了可能有不足的地方,或者各位有更好的解释,欢迎指点指点,先谢谢了~~~

猜你喜欢

转载自blog.csdn.net/weixin_40841731/article/details/85272513