前提需要明白 List 是引用类型,引用类型采用引用传递。
我们经常会遇到一些需求求集合的交集、差集、并集。例如下面两个集合:

  1. List<String> list1 = new ArrayList<String>();
  2. list1.add("A");
  3. list1.add("B");
  4. List<String> list2 = new ArrayList<String>();
  5. list2.add("B");
  6. list2.add("C");

求差集

例如,求 List1 中有的但是 List2 中没有的元素:

  1. public static void test3(List list1, List list2) {
  2. list1.removeAll(list2);
  3. System.out.println(list1);
  4. }

结果:

  1. [A]

查看 ArrayList 的 removeAll 的源码

  1. public boolean removeAll(Collection<?> c) {
  2. Objects.requireNonNull(c); return batchRemove(c, false);
  3. }

再查看 batchRemove 的源码:(如果传的第二个参数是 false,保留差集;如果传的是 true,保留的是交集)

  1. private boolean batchRemove(Collection<?> c, boolean complement) {
  2. final Object\[\]elementData = this.elementData;
  3. int r = 0, w = 0;
  4. boolean modified = false;
  5. try {
  6. for (; r < size; r++) if (c.contains(elementData\[r\]) ==complement)
  7. elementData\[w++\] =elementData\[r\];
  8. } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws.
  9. if (r != size) {
  10. System.arraycopy(elementData, r,
  11. elementData, w,
  12. size - r);
  13. w += size - r;
  14. }
  15. if (w != size) { // clear to let GC do its work
  16. for (int i = w; i < size; i++)
  17. elementData\[i\] =null;
  18. modCount += size - w;
  19. size = w;
  20. modified = true;
  21. }
  22. } return modified;
  23. }

是重新定义 elementData 数组的元素,下面代码的作用是将本集合中不包含另一个集合的元素重新加入元素,以此实现删除的功能(注意上面调用的方法传的参数是 false,也就是不包含的元素得以保留,实现差集的功能)

  1. if (c.contains(elementData[r]) == complement) {
  2. elementData[w++] = elementData[r];
  3. }

1.求并集(不去重)—-将一个集合全部加入另一个集合

  1. public static void test(List list1, List list2) {
  2. list1.addAll(list2);
  3. System.out.println(list1);
  4. }

结果:

  1. [A, B, B, C]

查看 ArayList 的 addAll()源码是数组复制:

  1. public boolean addAll(Collection<? extends E> c) {
  2. Object[] a = c.toArray();
  3. int numNew = a.length;
  4. ensureCapacityInternal(size + numNew); // Increments modCount
  5. System.arraycopy(a, 0, elementData, size, numNew);
  6. size += numNew;
  7. return numNew != 0;
  8. }

再查看 System 的 arraycopy 发现是一个 native 方法(本地方法):—-其实 system 类的好多方法都是 native 方法

  1. public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

2.求并集(去重)

例如:求 List1 和 List2 的并集,并实现去重。

思路是:先将 list 中与 list2 重复的去掉,之后将 list2 的元素全部添加进去。

  1. public static void test1(List list1, List list2) {
  2. list1.removeAll(list2);
  3. list1.addAll(list2);
  4. System.out.println(list1);
  5. }

结果:

  1. [A, B, C]

3.求交集

例如:求 List1 和 List2 中都有的元素。

  1. public static void test2(List list1, List list2) {
  2. list1.retainAll(list2);
  3. System.out.println(list1);
  4. }

结果:

  1. [B]

在上面 2 的实验过程中,我们知道 batchRemove(Collection,true)也是求交集,所以猜想 retainAll 内部应该是调用batchRemove(Collection,true),查看 ArrayList 的源码如下:

  1. public boolean retainAll(Collection<?> c) {
  2. Objects.requireNonNull(c); return batchRemove(c, true);
  3. }