0
点赞
收藏
分享

微信扫一扫

List中的并集、交集、差集的使用(并阅读源码)

  1. 总结

    1. 交集:两个list集合共同元素部分,retainAll()方法。
    2. 差集:从A集合中获取B集合中,没有的元素。removeAll()方法。
    3. 并集:将两个list集合并在一起,addAll()方法,但有可能出现重复元素,可以先removeAll(),去掉重复元素部分,再addAll()方法。
  2. 代码演示

    1. 交集:retainAll()方法

      package com.example.demo.list;
      
      import lombok.*;
      
      import java.util.ArrayList;
      import java.util.List;
      
      public class demo {
          public static void main(String[] args) {
              List<Person> list = new ArrayList<>();
              list.add(new Person("小明","18"));
              list.add(new Person("中明","28"));
              list.add(new Person("大明","38"));
              list.add(new Person("老明","48"));
      
              List<Person> list2 = new ArrayList<>();
              list2.add(new Person("小明","18"));
              list2.add(new Person("老明","48"));
              list2.add(new Person("老大明","58"));
              list2.add(new Person("老老明","68"));
      
              // 交集:共同元素部分
              list.retainAll(list2);
              System.out.println(list);
          }
      
          @Data
          @NoArgsConstructor
          @AllArgsConstructor
          static class Person{
              private String name;
              private String age;
          }
      }
      
      

      在这里插入图片描述

    2. 差集:removeAll()方法

      package com.example.demo.list;
      
      import lombok.*;
      
      import java.util.ArrayList;
      import java.util.List;
      
      public class demo {
          public static void main(String[] args) {
              List<Person> list = new ArrayList<>();
              list.add(new Person("小明","18"));
              list.add(new Person("中明","28"));
              list.add(new Person("大明","38"));
              list.add(new Person("老明","48"));
      
              List<Person> list2 = new ArrayList<>();
              list2.add(new Person("小明","18"));
              list2.add(new Person("老明","48"));
              list2.add(new Person("老大明","58"));
              list2.add(new Person("老老明","68"));
      
              // 差集:从A集合中获取B集合中,没有的元素
              list.removeAll(list2);
              System.out.println(list);
          }
      
          @Data
          @NoArgsConstructor
          @AllArgsConstructor
          static class Person{
              private String name;
              private String age;
          }
      }
      
      

      在这里插入图片描述

    3. 并集:removeAll(),去掉重复元素部分,再addAll()方法。

      package com.example.demo.list;
      
      import lombok.*;
      
      import java.util.ArrayList;
      import java.util.List;
      
      public class demo {
          public static void main(String[] args) {
              List<Person> list = new ArrayList<>();
              list.add(new Person("小明","18"));
              list.add(new Person("中明","28"));
              list.add(new Person("大明","38"));
              list.add(new Person("老明","48"));
      
              List<Person> list2 = new ArrayList<>();
              list2.add(new Person("小明","18"));
              list2.add(new Person("老明","48"));
              list2.add(new Person("老大明","58"));
              list2.add(new Person("老老明","68"));
      
              // 并集
              list.removeAll(list2);
              System.out.println("先获取list集合中不存在list2集合的元素:");
              System.out.println(list);
              list.addAll(list2);
              System.out.println("再将list2集合直接加到list集合中,达到去重的并集");
              System.out.println(list);
          }
      
          @Data
          @NoArgsConstructor
          @AllArgsConstructor
          static class Person{
              private String name;
              private String age;
          }
      }
      
      

      在这里插入图片描述

  3. 源码原理

    1. 交集(retainAll())

      public boolean retainAll(Collection<?> c) {
      		// 先判断是否为null
              Objects.requireNonNull(c);
              // 调用批量移动方法
              return batchRemove(c, true);
          }
      
    2. 差集(removeAll())

       public boolean removeAll(Collection<?> c) {
              Objects.requireNonNull(c);
              return batchRemove(c, false);
          }
      
    3. 通过查看上面两个源码,发现都是调用了同一个batchRemove方法,只是最后传递的boolean不一样。

    4. batchRemove()方法:

       private boolean batchRemove(Collection<?> c, boolean complement) {
       		// 设现是 集合ListA.retainAll(ListB) 则complement为true
       		// 先把ListA的元素赋给elementData变量
              final Object[] elementData = this.elementData;
              int r = 0, w = 0;
              boolean modified = false;
              try {
              	// 核心部分 size 是 ListA集合元素的个数
                  for (; r < size; r++)
                  	// 通过对 ListA的元素进行遍历
                  	// 判断ListA的元素是否在ListB元素中,得到的结果再跟comlement进行比较
                  	// 上述已设调用方法:集合ListA.retainAll(ListB) 则complement为true
                  	// 则 如果ListB元素包含ListA元素的话,则会返回true == complement,走到分支
                      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
                      // 将其他赋予null 为了更好的GC
                      for (int i = w; i < size; i++)
                          elementData[i] = null;
                      modCount += size - w;
                      size = w;
                      modified = true;
                  }
              }
              return modified;
          }
      

      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    5. addAll()方法:

      public boolean addAll(int index, Collection<? extends E> c) {
                  rangeCheckForAdd(index);
                  int cSize = c.size();
                  if (cSize==0)
                      return false;
      
                  checkForComodification();
                  // 核心
                  parent.addAll(parentOffset + index, c);
                  this.modCount = parent.modCount;
                  this.size += cSize;
                  return true;
              }
      
       public boolean addAll(int index, Collection<? extends E> c) {
              rangeCheckForAdd(index);
              boolean modified = false;
              // 就是很普通的遍历,一个个add
              for (E e : c) {
                  add(index++, e);
                  modified = true;
              }
              return modified;
          }
      
举报

相关推荐

0 条评论