Java集合:Collections與Collection的區別

前言

印象中,Collections像是一個工具箱,裏面有着集合類的各種幫助性質的方法,如reverse()等。而Collection是集合類的上級接口,繼承它的主要接口有List和Set,而List和Set的實現類也需要實現Collection定義的方法。

本文主要對Collections和Collection的區別進行介紹:

  • Collections與Collection在類型上的區別
    • Collections類型
    • Collection類型
  • Collections與Collection的常用方法
    • Collections常用方法
    • Collection常用方法

(若文章有不正之處,或難以理解的地方,請多多諒解,歡迎指正)

Collections與Collection在類型上的區別

Collections類型

前言提到,Collections是一個包含集合類的各種幫助性質方法的工具,服務於Java的Collection類及其子類。

在這裏插入圖片描述

Collection類型

Collection是一個集合接口,提供了對集合對象進行基本操作的通用接口方法,有很多實現Collection接口的實現,如ArrayList、HashSet等。Collection接口的意義在於爲各種具體的集合提供了最基本的統一操作方式。
在這裏插入圖片描述

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的區別

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章