在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类中的静态变量,类型为整形,默认为
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;
}

数组元素交换方法如上。

JDK之集合乱序源码分析的更多相关文章

  1. 死磕 java集合之ConcurrentHashMap源码分析(三)

    本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...

  2. 死磕 java集合之DelayQueue源码分析

    问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...

  3. 死磕 java集合之PriorityBlockingQueue源码分析

    问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...

  4. 死磕 java集合之PriorityQueue源码分析

    问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...

  5. 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计

    问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...

  6. 死磕 java集合之LinkedHashSet源码分析

    问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...

  7. 死磕 java集合之ArrayDeque源码分析

    问题 (1)什么是双端队列? (2)ArrayDeque是怎么实现双端队列的? (3)ArrayDeque是线程安全的吗? (4)ArrayDeque是有界的吗? 简介 双端队列是一种特殊的队列,它的 ...

  8. 死磕 java集合之LinkedList源码分析

    问题 (1)LinkedList只是一个List吗? (2)LinkedList还有其它什么特性吗? (3)LinkedList为啥经常拿出来跟ArrayList比较? (4)我为什么把LinkedL ...

  9. 【死磕 Java 集合】— ConcurrentSkipListMap源码分析

    转自:http://cmsblogs.com/?p=4773 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...

随机推荐

  1. PHP Socket(套接字连接)扩展简介和使用方法

    PHP socket扩展是基于流行的BSD sockets,实现了和socket通讯功能的底层接口,它可以和客户端一样当做一个socket服务器. 使用这些函数时请注意,虽然他们中有很多和C函数同名的 ...

  2. 03_模拟DVD

    package com.entity; import java.text.SimpleDateFormat; import java.util.Date; public class DVD { pri ...

  3. ubuntu15.10运行android studio出错unable to run mksdcard sdk tool

    问题:ubuntu运行android studio出错unable to run mksdcard sdk tool 系统版本:系统是ubuntu 15.10 64位 确认原因:缺少lib 解决方法: ...

  4. ASP.NET MVC 中使用用户控件——转

    讲讲怎么在 ASP.NET MVC2中使用用户控件.首先我们新建一个用户控件,   我们命名为SelectGroup.ascx,代码如下 <%@ Control Language="C ...

  5. MySQL单独存放表空间Innodb_file_per_table

    在mysql中Innodb_file_per_table参数的作用是什么呢,其实许多的朋友是不知道的,今天我们来看这篇MySQL单独存放表空间Innodb_file_per_table参数详解之后你就 ...

  6. localhost与127.0.0.1之间的区别

    Localhost的意思是本地服务器,而127.0.0.1是本机地址,他们的关系是通过操 作系统中的hosts文件,将Localhost解析为127.0.0.1.而实际工作中,Localhost是不经 ...

  7. 使用git将代码推到coding

    1:前提下载好Git 2:在电脑上创建一个文件夹,打开此文件夹,单击右键—〉 git bash here 3:输入git init 完成后会在此文件夹下生成一个隐藏的.git后缀文件 4:将你的代码添 ...

  8. Underscore template

    /********************************************************************* * Underscore template * 说明: * ...

  9. OK335x mksd.sh hacking

    #! /bin/sh # mk3PartSDCard. # Licensed under terms of GPLv2 # 参考文档: # . sfidsk创建可启动分区问题 # http://seg ...

  10. HDU3652 B-number 数位DP第二题

    A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- ...