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对象,然后调用第二个方法,所以我们来看第二重载形式的实现。全部代码如下:

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接口,则直接调用集合交换方法。

RandomAccess是一个空接口,个人的理解和Serializable接口一样,起到一个标识的作用,在这里标识集合类是否支持随机访问。

如果支持则随机访问,或者元素个数<5,则直接调用集合交换的swap方法来交换元素(毕竟即使集合不支持RandomAccess,5个

之内的元素交换也不会影响什么性能)。

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

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

数组元素交换方法如上。

 

posted @ 2017-08-29 15:46  框架搬运工  阅读(528)  评论(0编辑  收藏  举报