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

    数组元素交换方法如上。

  • 相关阅读:
    过滤器
    自定义指令
    Window setTimeout() 方法
    Window setInterval()方法
    ThingJS官方案例(五):物联网室内3D定位导航,上下楼怎么办?
    基于WebGL的虚拟太阳系漫游技术实现 ThingJS 科幻片
    ThingJS官方案例(四):快速应用3D场景下的模拟导航能力
    ThingJS官方示例(三):3D标记“Marker”跳跃、闪烁和发光动画效果
    ThingJS官方示例(二):利用电子标注判断物联网设备的位置
    ThingJS 官方示例(一):禁区告警的3D电子围栏可视化
  • 原文地址:https://www.cnblogs.com/leemz-coding/p/7448595.html
Copyright © 2020-2023  润新知