You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用removeAll移除列表子列表为何出现不同结果?

问题分析:两段ArrayList removeAll代码的差异原因

先看两段代码及运行结果:

第一段代码:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(0);
list.add(0);
list.removeAll(list.subList(0, 1));
System.out.println(list);

运行结果:[0]

第二段代码:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(0);
list.add(1);
list.removeAll(list.subList(0, 1));
System.out.println(list);

运行结果:[0, 1]


核心原因:subList是原列表的视图 + ArrayList batchRemove的实现逻辑

  1. subList的本质:list.subList(0,1)返回的不是新列表,而是原ArrayList的视图,它直接引用原列表的底层数组,视图的内容会随原数组的修改实时变化。
  2. ArrayList.removeAll的实现逻辑:removeAll内部调用batchRemove方法,核心逻辑是遍历原数组,把不需要移除的元素覆盖到数组前半部分,最后截断数组。关键在于:遍历过程中会直接修改原数组元素,subList的内容会同步变化,进而影响后续的元素判断。

第一段代码的详细执行过程

原列表初始底层数组:[1, 0, 0],size=3,subList(0,1)的内容是原数组索引0的元素1。

  • r=0:当前元素是1,调用subList.contains(1)返回true,因此不保留该元素,w(保留元素的指针)保持0,r自增到1。
  • r=1:当前元素是0,调用subList.contains(0)返回false(此时subList内容还是1),因此将该元素覆盖到数组索引0的位置,数组变为[0, 0, 0],w自增到1,r自增到2。
  • r=2:当前元素是0,此时subList的内容已经因为原数组的修改变成了0,调用subList.contains(0)返回true,因此不保留该元素,w保持1,r自增到3,循环结束。
  • 最后截断数组,size设为1,最终列表为[0]。

第二段代码的详细执行过程

原列表初始底层数组:[1, 0, 1],size=3,subList(0,1)的内容是1。

  • r=0:当前元素是1,subList.contains(1)返回true,不保留,w=0,r=1。
  • r=1:当前元素是0,subList.contains(0)返回false,覆盖到数组索引0的位置,数组变为[0, 0, 1],w=1,r=2。此时subList内容变为0。
  • r=2:当前元素是1,调用subList.contains(1)返回false(subList内容是0),因此将该元素覆盖到数组索引1的位置,数组变为[0, 1, 1],w=2,r=3,循环结束。
  • 截断数组,size设为2,最终列表为[0, 1]。

总结

两段代码的差异源于:removeAll遍历过程中修改原数组,导致subList的内容实时变化,进而影响后续元素是否被移除的判断。第一段代码中第二个0因为subList内容变为0而被判定为需要移除,第二段代码中的1因为subList内容变为0而被判定为不需要移除。

内容的提问来源于stack exchange,提问作者Suttonese

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 05:25:56