Collections类中的shuffle方法源码分析

IT教程 4年前 (2020) https://www.leileyou.com

collections.shuffle

Collections类中的shuffle方法源码分析

shuffle方法可以将List中的数据随机打乱顺序,之前我们就使用了这个方法实现了扑克牌的洗牌功能,下面来看下shuffle方法的源码:

public static void shuffle(List<?> list) {
    Random rnd = r;
    if (rnd == null)
        r = rnd = new Random(); // harmless race.
    shuffle(list, rnd);
}

该方法中获取了一个随机数的对象,之后调用了与其构成重载的另一个shuffle方法:

 @SuppressWarnings({"rawtypes", "unchecked"})
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方法有个逻辑判断,第一个判断是当List对象的长度小于5或者List对象是RandomAccess实例的时候直接执行了for循环,在这个for循环中调用了swap方法:

@SuppressWarnings({"rawtypes", "unchecked"})
public static void swap(List<?> list, int i, int j) {
    // 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
    final List l = list;
    l.set(i, l.set(j, l.get(i)));
}

在这个swap方法中可以看到,

swap方法中接收的参数j是一个随机数,将这个随机数j作为索引位置,直接调用了list中的set方法来修改list中的数据。这个其实就相当于是使用了基本的for循环和随机数来实现的随机打乱list中的数据顺序。

再回到shuffle方法,在逻辑判断中还有一个else,在这个里面的做法是先将list转换为数组,之后使用for循环和随机数来随机打乱该数组的顺序,最后使用了迭代器来将这个数组中的数据放入到list中,这样就相对于随机的改变了list中的数据顺序。

        //将list转换为数组
        Object arr[] = list.toArray();

        // 随机打乱数组中的顺序
        for (int i=size; i>1; i--)
            swap(arr, i-1, rnd.nextInt(i));

        //使用迭代器将数组中的数据放入到list集合中
        ListIterator it = list.listIterator();
        for (int i=0; i<arr.length; i++) {
            it.next();
            it.set(arr[i]);
        }

以上就是shuffle方法的源码简要分析。这里有一个问题,就是为什么在shuffle方法中要有一个逻辑判断呢?直接修改list中数据的顺序不就行了吗。这个就跟list有关系了,List只是一个接口,有一些他的实现类,最具代表性的是ArrayList和LinkedList。

当调用shuffle方法时传入的是ArrayList的话,因为ArrayList实现了RandomAccess接口,那么就会执行if中的代码,这里面的做法是使用一个基本for循环直接修改list中的数据。

当调用shuffle方法时传入的是LinkedList的话,就会执行else中的代码,他在里面先将其转换为数组,然后再将数组中的元素使用迭代器再重新放入到LinkedList中。

在使用基本for循环对ArrayList和LinkedList进行遍历的时候,ArrayList的运行效率要远比LinkedList高,这是因为ArrayList底层使用数组实现,所以通过下标访问的话ArrayList效率高。

当时用迭代器或者增强for循环(底层就是使用的迭代器)遍历ArrayList和LinkedList时,因为LinkedList底层使用链表实现,所以LinkedList的效率远比ArrayList高。

由于以上的原因,为了程序的效率,所以在shuffle方法中使用了逻辑判断来区分具体是哪一种List从而高效的对其进行遍历。

用excel表格做排班表的方法步骤详解

Excel是三大办公软件之一的一个软件,他经常用于数据的整理、分析、以及对比等。而有很多时候需要用到Excel里的图表功能进行制作排

vagaa下载速度慢的解决方法

首先在下载的时候要看资源哟、~~资源多的 当然下载速度快咯、~嘻嘻、然后就是 VAGAA 是共享的 P2P 格式的文件下载 、全球都在用

阻力设计的正确使用方法

信息阻力是指用户实现最终目标或完成某件事情时受到的阻力,如何正确的使用阻力设计呢?一、何为阻力设计何为信息阻力呢?我们可以把信

SSD怎么安装 台式机与笔记本安装固态硬盘方法步骤

固态硬盘已经逐渐成为了电脑的标配,SSD解决了以往机械硬盘的性能瓶颈,在开关机速度、流畅度方面表现出了更佳的体验。目前,不论是台

小编告诉你任务栏突然变宽了的恢复方法

我们平时在使用电脑的过程中经常都会遇到各种各样的问题。就比如说任务栏变宽的情况,想必有不少的小伙伴在遇到这个问题的时候都是

文章回顾

大家看了本文Collections类中的shuffle方法源码分析的精彩教程资源内容,是不是对Collections类中的shuffle方法源码分析了解更多,真心希望Collections类中的shuffle方法源码分析能帮助到你, 小编会一直给你带来更多教程资源文章信息。

版权声明: 发表于 2020-08-04 8:50:37。

本文在撰写过程中会借鉴文案,对内容不作任何保证或承诺,请读者自行参考斟酌。网站发布的信息(包含但不限于版式、图片、字体、文章等素材)由第三方用户分享,版权归原作者所有,本站不承担任何相关的版权纠纷等相关责任。如您认为本篇内容侵犯了您的权益,请与我们联系,我们会及时处理。

本文标题:Collections类中的shuffle方法源码分析