今天给大家介绍下ArrayList之removeAll的用法,并深入讲解一下它的底层实现原理。
大家先看如下所示代码:
CollectionTest collectionTest =new CollectionTest();
List<DataDto> list1 =new ArrayList<>();
for(int i=1;i<=10;i++){
DataDto dataDto =new DataDto(i+"");
list1.add(dataDto);
}
List<DataDto> list2 =new ArrayList<>();
DataDto dataDto1 =new DataDto("2");
list2.add(dataDto1);
list1.removeAll(list2);
collectionTest.print(list1);
不知道大家猜到结果了没,结果就是DataDto(“2”)并没有被移除掉,我们将list1集合打印出来,显示集合没有任何一个元素被删除。
1
2
3
4
5
6
7
8
9
10
下面我们再看看下面这个案例代码:
CollectionTest collectionTest =new CollectionTest();
List<DataDto> list1 =new ArrayList<>();
for(int i=1;i<=10;i++){
DataDto dataDto =new DataDto(i+"");
list1.add(dataDto);
}
List<DataDto> list2 =list1.subList(0,2);
list1.removeAll(list2);
collectionTest.print(list1);
这个情况下,removeAll成功的将1、2两个元素移除掉了。结果如下所示:
3
4
5
6
7
8
9
10
这到底是什么情况呢,为什么发生这种情况呢?莫着急,我们看一下removeAll底层的源码是如何实现的。ArrayList底层源码如下所示:
public boolean removeAll(Collection<?> c) {
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 {
// 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;
}
第一步:
先判断要移除的集合是否为null,如果为null则抛出null异常。
第二步:
如果不为null,则接着调用batchRemove方法即可移除成功。
代码的原理可以简单概述为如下过程:
备注:
System.arraycopy主要作用是为了防止contains出现异常,导致集合出现问题。
从源码可以看出,上面案例一之所以移除不成功的原因是因为:contains底层是通过equals实现的,所以对比的是元素的堆地址。而案例一的移除对象是新new出来的,所以不是同一个地址,所以也当然移除不了。
源码就分析到这边了,原理其实很简单。平时大家在写业务代码的时候,一定要抽空去了解代码背后的实现原理,这样才能深入的成长。
林老师带你学编程:https://wolzq.com