欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ArrayList源码(2)

程序员文章站 2022-07-14 12:05:56
...

现在接着说ArrayList的另外一个常用方法remove().
remove同样也是存在两个方法
1.

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);
    elementData[--size] = null; // Let gc do its work

    return oldValue;
}

第一步和add里面rangeCheckForAdd(index);相似但是并不完全相同

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

并没有判断index<0的情况,这个为什么呢?我没有想明白运行肯定出现错误

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.ArrayList.elementData(ArrayList.java:371)
    at java.util.ArrayList.remove(ArrayList.java:448)
    at Test.DateTest.main(DateTest.java:21)

难道是因为肯定会报错就不用判断了??恕我才能浅薄,大家如果有知道的请告诉我一声。
之后把将要移除的数据拿出并返回,数组的长度进行改变之后执行数组复制的操作,我找了个该方法说明的博客: System.arraycopy方法的使用。最后将数组的最后一位设置为null。
2.

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

这个分两种情况传来的值是否为null,如果为null,则进行对比,是否List数组中是否有null,然后将其删除,如果不是同样是遍历List来对比。
将数据从List数组中移除的方法又是:

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; // Let gc do its work
}

这段代码在remove(index)里面都有,那为什么不写成这样呢?

public E remove(int index) {
    rangeCheck(index);

    E oldValue = elementData(index);
    fastRemove(index);

    return oldValue;
}

大家想想为什么??说出来
接下来是remove的另外两个方法:

public boolean removeAll(Collection<?> c) {
    return batchRemove(c, false);
}

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

全用到了batchRemove只是传的第二个参数不同。

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) {
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}

大家应该知道removeAll是将相同的都删除, 留下不相同的。retainAll是将不相同的都删除,留下相同的。
代码简单,注意他们最后再遍历一遍将空出的个数最后几个都设置为null。这个在之后大家写相关的代码时一定要注意。
remove的内容都说完了,还有一个相似的clear(),这个没有啥内容。

public void clear() {
    modCount++;

    // Let gc do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}