JDK之集合亂序源碼分析

在JAVA的JDK中Collections類提供了shuffle方法用來對給定的集合參數進行亂序重排,以前面試也被問到過相似的問題,看了一下JDK的源碼實現作個記錄面試

1. 方法簽名:數組

  Collections.shuffle方法提供了兩個重載的形式分別爲:數據結構

1. public static void shuffle(List<?> list)
2. public static void shuffle(List<?> list, Random rnd)

在實現上,第一個方法中new了Random對象,而後調用第二個方法,因此咱們來看第二重載形式的實現。所有代碼以下:dom

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));

            // Dump array back into list
            // instead of using a raw type here, it's possible to capture
            // the wildcard but it will require a call to a supplementary
            // private method
            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }

代碼解釋:性能

SHUFFLE_THRESHOLD 爲Collections類中的靜態變量,類型爲整形,默認爲5
if判斷中,首先判斷要亂序的集合大小,若是集合大小<5,或者集合類型實現了RandomAccess接口,則直接調用集合交換方法。ui

RandomAccess是一個空接口,我的的理解和Serializable接口同樣,起到一個標識的做用,在這裏標識集合類是否支持隨機訪問。spa

若是支持則隨機訪問,或者元素個數<5,則直接調用集合交換的swap方法來交換元素(畢竟即便集合不支持RandomAccess,5個code

以內的元素交換也不會影響什麼性能)。對象

再看一下集合元素交換的方法:blog

public static void swap(List<?> list, int i, int j) {
        final List l = list;
        l.set(i, l.set(j, l.get(i)));
}

就這麼兩行代碼,不過這裏有一點沒看懂的是:爲何要聲明一個final類型的List來接收參數中的List對象?不明白

交換的規則也很簡單,變量 i 是循環內獲取的集合的size值-1,也就是集合的最後一個元素,將最後一個元素的值

設置爲集合中位置 j 的值,j 的值是random.nextInt(i)來隨機獲取的集合中的某個位置索引。

因此交換規則就是:

  循環,每次將數組的最後一個元素和一個隨機獲取到的元素進行交換。

再來看else分支中:

  能進到else分支,說明集合對象沒有實現RandomAccess接口,好比LinkedList沒有實現RandomAccess,由於

數據結構的特性,若是訪問LinkedList中的元素只能遍歷,若是元素多,訪問的元素還靠後,訪問性能不好,因此JDK在這裏

將集合首先轉爲數組,而後調用數組的元素交換方法,交換規則和以前的規則同樣。由於數組有下標,支持隨機訪問,

因此這樣亂序會提升性能。

private static void swap(Object[] arr, int i, int j) {
    Object tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

數組元素交換方法如上。

相關文章
相關標籤/搜索