• ArrayList的removeAll和retainAll方法


    一、含义

    1、removeAll方法 从list中删除指定集合中包含的所有元素

    2、retainAll方法  从list中删除指定集合中不包含的所有元素

    二、源码:

    1、removeAll源码

    1. public boolean removeAll(Collection c) {
    2. Objects.requireNonNull(c);//判断参数是否为空
    3. return batchRemove(c, false);//删除指定集合中包含的所有元素
    4. }

    2、retainAll源码

    1. public boolean retainAll(Collection c) {
    2. Objects.requireNonNull(c);//判断参数是否为空
    3. return batchRemove(c, true);//删除指定集合中不包含的所有元素
    4. }

    判断参数是否为空的方法暂不考虑,两个方法都调用了batchRemove方法,只是第二个参数传递不同,一个是false一个是true

    3、batchRemove源码

    1. //用removeAll方法说明(complement = false)
    2. private boolean batchRemove(Collection c, boolean complement) {
    3. //elementData是arraylist中存储数据的数组
    4. final Object[] elementData = this.elementData;
    5. //r控制循环、w控制elementData的下表
    6. int r = 0, w = 0;
    7. boolean modified = false;
    8. try {
    9. //举例说明for循环
    10. //原数组elementData中的数据["a","b","c","d","e"]
    11. //参数的Collection假设为arraylist,数组是["b","c","d"]
    12. //for循环第一轮 r=0,w=0判读语句(c.contains(elementData[r]) == complement)为true
    13. //进入if的代码块 elementData[w++] = elementData[r];
    14. //也就是elementData[0] = elementData[0] 即elementData[0]=a; w自增
    15. //for循环第二轮 r=1,w=1判读语句(c.contains(elementData[r]) == complement)为false
    16. //for循环第三轮 r=2,w=1判读语句(c.contains(elementData[r]) == complement)为false
    17. //for循环第四轮 r=3,w=1判读语句(c.contains(elementData[r]) == complement)为false
    18. //for循环第五轮 r=4,w=1判读语句(c.contains(elementData[r]) == complement)为true
    19. //进入if的代码块 elementData[w++] = elementData[r];
    20. //也就是elementData[1] = elementData[4] 即elementData[1]=e; w自增
    21. //循环完成后elementData中的数据["a","e","c","d","e"](注意第二个元素) r=5 w=2
    22. for (; r < size; r++)
    23. if (c.contains(elementData[r]) == complement)
    24. elementData[w++] = elementData[r];
    25. } finally {
    26. //如果contains方法使用过程报异常,将剩下的元素都赋值给集合elementData
    27. if (r != size) {
    28. System.arraycopy(elementData, r, elementData, w, size - r);
    29. w += size - r;
    30. }
    31. //将elementData[w]之后的数据置空
    32. if (w != size) {
    33. for (int i = w; i < size; i++)
    34. elementData[i] = null;
    35. modCount += size - w;
    36. size = w;
    37. modified = true;
    38. }
    39. //完成后elementData中的数据["a","e",null,null,null]
    40. }
    41. return modified;
    42. }

    4、在batchRemove方法中的判断语句if (c.contains(elementData[r]) == complement)中的contains方法

    1. //以arraylist为例
    2. public boolean contains(Object o) {
    3. //调用了indexOf方法
    4. return indexOf(o) >= 0;
    5. }

    5、在contains方法中调用了indexOf方法

    1. //以arraylist为例
    2. public int indexOf(Object o) {
    3. //null的情况暂不考虑
    4. if (o == null) {
    5. for (int i = 0; i < size; i++)
    6. if (elementData[i]==null)
    7. return i;
    8. } else {
    9. //循环调用,利用equals方法判断是否存在
    10. for (int i = 0; i < size; i++)
    11. if (o.equals(elementData[i]))
    12. return i;
    13. }
    14. return -1;
    15. }

    三、总结

    1、removeAll或者retainAll方法调用private方法batchRemove。

    2、batchRemove方法中有个判断语句调用了contains方法。

    3、contains方法中调用了indexOf方法。

    4、indexOf方法中调用equals方法。

    1. ArrayList list1 = new ArrayList();
    2. list1.add("a");
    3. list1.add("b");
    4. list1.add("c");
    5. list1.add("d");
    6. list1.add("e");
    7. ArrayList list2 = new ArrayList();
    8. list2.add("b");
    9. list2.add("c");
    10. list2.add("d");
    11. list1.removeAll(list2);
    12. for(String s : list1) {
    13. System.out.println(s);
    14. }

    上面的代码段可以得到预期的效果  输出 a e

    1. ArrayList personList1 = new ArrayList();
    2. ArrayList personList2 = new ArrayList();
    3. Person persona = new Person("a", 18);
    4. Person personb = new Person("b", 19);
    5. Person personc = new Person("c", 20);
    6. Person persond = new Person("d", 21);
    7. Person persone = new Person("e", 22);
    8. Person personf = new Person("b", 19);
    9. Person persong = new Person("c", 20);
    10. Person personh = new Person("d", 21);
    11. personList1.add(persona);
    12. personList1.add(personb);
    13. personList1.add(personc);
    14. personList1.add(persond);
    15. personList1.add(persone);
    16. personList2.add(personf);
    17. personList2.add(persong);
    18. personList2.add(personh);
    19. personList1.removeAll(personList2);
    20. for(Person p : personList1) {
    21. System.out.println(p.getName());
    22. }

    上面的代码段如果要用personList1.removeAll(personList2);得到预期的效果需要重写Person类的equals方法

    1. public class Person {
    2. private String name;
    3. private int age;
    4. public Person() {
    5. super();
    6. }
    7. public Person(String name, int age) {
    8. super();
    9. this.name = name;
    10. this.age = age;
    11. }
    12. public String getName() {
    13. return name;
    14. }
    15. public void setName(String name) {
    16. this.name = name;
    17. }
    18. public int getAge() {
    19. return age;
    20. }
    21. public void setAge(int age) {
    22. this.age = age;
    23. }
    24. //重写equals方法后 arraylist的removeAll方法能够得到预期的效果
    25. public boolean equals(Object obj) {
    26. if (this == obj) {
    27. return true;
    28. }
    29. if (obj instanceof Person) {
    30. Person p = (Person) obj;
    31. if (this.name.equals(p.getName()) && this.age == p.getAge()) {
    32. return true;
    33. } else {
    34. return false;
    35. }
    36. } else {
    37. return false;
    38. }
    39. }
    40. }

  • 相关阅读:
    Jmeter内置变量 vars 和props的使用详解
    java实现备忘录模式
    LeetCode50天刷题计划第二季(Day 28 — 最小栈(10.20- 10.50)
    SpringBoot - @ControllerAdvice注解详解
    3分钟告诉你如何成为一名黑客|零基础到黑客入门指南,你只需要掌握这五点能力
    Pandas表格样式,你有table-style吗
    【FPGA零基础学习之旅#17】搭建串口收发与储存双口RAM系统
    派对的最大快乐值
    542、RabbitMQ详细入门教程系列 -【延迟队列实现】 2022.09.05
    iNFTnews | 元宇宙会终结智能手机时代吗?
  • 原文地址:https://blog.csdn.net/zhangyong329/article/details/126504037