前言

印象中,Collections像是一个工具箱,里面有着集合类的各种帮助性质的方法,如reverse()等。而Collection是集合类的上级接口,继承它的主要接口有List和Set,而List和Set的实现类也需要实现Collection定义的方法。

本文主要对Collections和Collection的区别进行介绍:

  • Collections与Collection在类型上的区别
  • Collections类型
  • Collection类型
  • Collections与Collection的常用方法
  • Collections常用方法
  • Collection常用方法

(若文章有不正之处,或难以理解的地方,请多多谅解,欢迎指正)

Collections与Collection在类型上的区别

Collections类型

前言提到,Collections是一个包含集合类的各种帮助性质方法的工具,服务于Java的Collection类及其子类。

Java集合类中collection与map的区别 java中collection和collections的区别_后端

Collection类型

Collection是一个集合接口,提供了对集合对象进行基本操作的通用接口方法,有很多实现Collection接口的实现,如ArrayList、HashSet等。Collection接口的意义在于为各种具体的集合提供了最基本的统一操作方式。

Java集合类中collection与map的区别 java中collection和collections的区别_List_02

Collections与Collection的方法区别

Collections常用的方法

举个简单的栗子:

public static void main(String[] args){
    ArrayList<Integer> list = new ArrayList<>();
    list.add(3);
    list.add(1);
    list.add(2);
    list.add(6);
    list.add(5);
    list.add(4);
}
1. sort(Collection c)

对集合进行排序

public static <T extends Comparable<? super T>> void sort(List<T> list) {
	list.sort(null);  //直接使用list本身的sort()方法来实现排序
}

//[3, 1, 2, 6, 5, 4]
Collections.sort(list); //[1, 2, 3, 4, 5, 6]
2. shuffle(Collection c)

对集合进行随机排序

public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextInt(i));  //随机交换
        } else {
            Object arr[] = list.toArray();

            // Shuffle array  随机交换生成数组
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));

            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);  
            }
        }
    }
//[1, 2, 3, 4, 5, 6]
Collections.shuffle(list); //[2, 6, 3, 5, 1, 4]
3. reverse()

反转集合中元素的顺序

public static void reverse(List<?> list) {
        int size = list.size();
        if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
                swap(list, i, j);  //反转数组元素
        } else {
            //前后遍历反转数组
            ListIterator fwd = list.listIterator();
            ListIterator rev = list.listIterator(size);
            for (int i=0, mid=list.size()>>1; i<mid; i++) {
                Object tmp = fwd.next();
                fwd.set(rev.previous());
                rev.set(tmp);
            }
        }
    }

//[3, 1, 2, 6, 5, 4]
Collections.reverse(list);  //[4, 5, 6, 2, 1, 3]
4. fill(List list, Object o)

用对象o替换集合list中的所有元素

public static <T> void fill(List<? super T> list, T obj) {
        int size = list.size();
		//遍历集合,替换集合中的所有元素
        if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
            for (int i=0; i<size; i++)
                list.set(i, obj);  
        } else {
            ListIterator<? super T> itr = list.listIterator();
            for (int i=0; i<size; i++) {
                itr.next();
                itr.set(obj);
            }
        }
    }

//[3, 1, 2, 6, 5, 4]
Collections.fill(list, 0);  //[0, 0, 0, 0, 0, 0]
5. copy(List m, List n)

将集合n中的元素全部复制到m中,并且覆盖相应索引的元素

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
        int srcSize = src.size();
        if (srcSize > dest.size())
            throw new IndexOutOfBoundsException("Source does not fit in dest");

        if (srcSize < COPY_THRESHOLD ||
            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
            for (int i=0; i<srcSize; i++)  //将数组src中的数组复制到dest中
                dest.set(i, src.get(i));
        } else {
            //遍历两个集合,将一个集合的数据复制到另一个数组中
            ListIterator<? super T> di=dest.listIterator();
            ListIterator<? extends T> si=src.listIterator();
            for (int i=0; i<srcSize; i++) {
                di.next();
                di.set(si.next());
            }
        }
    }

//[3, 1, 2, 6, 5, 4]
List<Integer> list2 = new ArrayList<>();
list2.add(-100);
list2.add(-200);
list2.add(-300);
list2.add(-400);
list2.add(-500);
list2.add(-600);
Collections.copy(list, list2);  //[-100, -200, -300, -400, -500, -600]
6. rotate(List list, int m)

集合中的元素向后移动m个位置,在后面被遮盖的元素循环到前面来

public static void rotate(List<?> list, int distance) {
        if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
            rotate1(list, distance);
        else
            rotate2(list, distance);
    }

private static <T> void rotate1(List<T> list, int distance) {
        int size = list.size();
        if (size == 0)
            return;
		
    	//此处主要是对distance值进行处理
        distance = distance % size;
        if (distance < 0)
            distance += size;
        if (distance == 0)
            return;

    	//因为可能会出现后面的数据被覆盖的可能,所以需要多一个do...while...来进行处理
        for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
            T displaced = list.get(cycleStart);
            int i = cycleStart;
            do {
                i += distance;
                if (i >= size)
                    i -= size;
                displaced = list.set(i, displaced);
                nMoved ++;
            } while (i != cycleStart);
        }
    }

    private static void rotate2(List<?> list, int distance) {
        int size = list.size();
        if (size == 0)
            return;
        int mid =  -distance % size;
        if (mid < 0)
            mid += size;
        if (mid == 0)
            return;
		
        //根据distance与size的关系,将集合分成两段,分别进行反转,然后再将整个集合元素顺序进行反转
        reverse(list.subList(0, mid));
        reverse(list.subList(mid, size));
        reverse(list);
    }
//[3, 1, 2, 6, 5, 4]
Collections.rotate(list, 3);  //[6, 5, 4, 3, 1, 2]
7. max(Collection), max(Collection, Comparator)/min(Collection), min(Collection, Comparator)

前者采用Collection内置的自然比较法,后者采用Comparator制定的比较规则进行比较

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
        Iterator<? extends T> i = coll.iterator();
        T candidate = i.next();
		//遍历集合,选出最大值
        while (i.hasNext()) {
            T next = i.next();
            if (next.compareTo(candidate) > 0)
                candidate = next;
        }
        return candidate;
    }

public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) {
        Iterator<? extends T> i = coll.iterator();
        T candidate = i.next();
		//遍历集合,选出最小值
        while (i.hasNext()) {
            T next = i.next();
            if (next.compareTo(candidate) < 0)
                candidate = next;
        }
        return candidate;
    }
//[3, 1, 2, 6, 5, 4]
System.out.println(Collections.max(list));  //6
System.out.println(Collections.min(list));  //1
8. indexOfSubList(List list, List subList)

查找subList在list中首次出现的位置索引

public static int indexOfSubList(List<?> source, List<?> target) {
        int sourceSize = source.size();
        int targetSize = target.size();
    	//遍历source的次数,无需全部遍历
        int maxCandidate = sourceSize - targetSize;

        if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
            (source instanceof RandomAccess&&target instanceof RandomAccess)) {
        nextCand:
            //遍历source集合
            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
                //target集合中的元素与sourse集合中的元素进行比较
                for (int i=0, j=candidate; i<targetSize; i++, j++)
                    if (!eq(target.get(i), source.get(j)))
                        continue nextCand;  // Element mismatch, try next cand
                return candidate;  // All elements of candidate matched target
            }
        } else {  // Iterator version of above algorithm
            ListIterator<?> si = source.listIterator();
        nextCand:
            //依然是遍历两个集合
            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
                ListIterator<?> ti = target.listIterator();
                for (int i=0; i<targetSize; i++) {
                    if (!eq(ti.next(), si.next())) {
                        // Back up source iterator to next candidate
                        //如果ti.next()与si.next()不相等,则需要将迭代器指针位置移回source集合的首位
                        for (int j=0; j<i; j++)
                            si.previous();
                        continue nextCand;
                    }
                }
                return candidate;
            }
        }
        return -1;  // No candidate matched the target
    }

//[3, 1, 2, 6, 5, 4]
List<Integer> list2 = new ArrayList<>();
list2.add(2);
list2.add(6);
System.out.println(Collections.indexOfSubList(list, list2));  //2
9. replaceAll(List list, Object old, Object new)

替换批定元素为某元素,若要替换的值存在则返回true,反之返回false

public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
        boolean result = false;
        int size = list.size();
        //遍历集合,找到要替换的元素后进行替换操作
        if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) {
            //如果替换的元素是null,则需要单独处理
            if (oldVal==null) {
                for (int i=0; i<size; i++) {
                    if (list.get(i)==null) {
                        list.set(i, newVal);
                        result = true;
                    }
                }
            } else {
                for (int i=0; i<size; i++) {
                    if (oldVal.equals(list.get(i))) {
                        list.set(i, newVal);
                        result = true;
                    }
                }
            }
        } else {
            ListIterator<T> itr=list.listIterator();
            //同上
            if (oldVal==null) {
                for (int i=0; i<size; i++) {
                    if (itr.next()==null) {
                        itr.set(newVal);
                        result = true;
                    }
                }
            } else {
                for (int i=0; i<size; i++) {
                    if (oldVal.equals(itr.next())) {
                        itr.set(newVal);
                        result = true;
                    }
                }
            }
        }
        return result;
    }

//[3, 1, 2, 6, 5, 4]
Collections.replaceAll(list, 2, 200);  //[3, 1, 200, 6, 5, 4]
10. swap(List list, int i, int j)

交换集合中指定元素索引的位置

public static void swap(List<?> list, int i, int j) {
        
        final List l = list;
        l.set(i, l.set(j, l.get(i)));  //当使用l.set()方法时会返回替换位置原先的数据
    }

//[3, 1, 2, 6, 5, 4]
Collections.swap(list, 2, 5);  //[3, 1, 4, 6, 5, 2]

Collection的方法

Collection是集合接口,因子类如ArrayList、LinkedList、HashSet等的底层结构不同,所以其方法实现在各子类也是有所不同,此处不进行赘述,有兴趣的朋友可以看笔者之前文章,或者关注笔者,笔者后续还会写Java集合系列的文章。

结语

其实Collections与Collection最本质的区别就在于,一个是类,一个是接口;而且它们之间的关系是,一个是工具,一个是被操作者。

本文主要对final关键字进行介绍,如果本文对你有帮助,请给一个赞吧,这会是我最大的动力~

参考资料

Collections类常用方法总结

Collection和Collections的区别及Collections常用方法

Java中Collection和Collections的区别