if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
这三个方法用来检查下表是否越界,如果越界就抛异常,以及异常的错误信息。
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
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;
}
这三个方法一起看,前两个方法分别是删除参数中所有元素的方法和保留参数中所有元素的方法。这两个方法都调用第三个方法,只是分别传给第三个方法不同的boolean参数。
第三个方法首先获取底层数组,并赋值给一个final的同名临时变量。
然后定义变量r和w都为0。然后定义布尔值变量modified默认为false,代表数组已经更改。
然后进入for循环,变量r进行循环自增,循环size次,也就是底层数组的长度次。进入循环后先判断参数集合是否是否包含本集合底层数组每一个元素,如果是第一个方法调进来的,且不包含,那么第r个元素将赋给第w个元素,然后w自增,举个例子,假设集合{1,2,3,4}调用第一个方法参数是{1,2,3}那么循环遍历时,4这个元素就到了第一位,因为先循环1,2,3发现参数中有1,2,3所以不处理,参数中没有4就进行处理,将4复制到第一位。
finally块里如果r最后不等于size,就将底层数组的第r位开始复制到w处,复制size-r个,这个是判断是否出现异常,如果不出现异常或线程不安全的情况r肯定是等于size的,w也会等于size,就是让没有进行遍历的数组元素复制到数组中用来恢复原状。。。然后将r与size相差的位数加给w。
如果w不等于size,也就是说已经将该移位的元素进行了移位,该将该删除的元素删除的时候,w处之后的元素全部设为空值。size赋值为w,modified变为true代表对数组进行了修改,modCount位size减去w次。最后返回modified。
第二个方法道理相同就是判断的条件略微不同,不多赘述了,不难理解。