在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. 2018.11.16 RX- IC

    1. IC内部组成: Reference Oscillator:基准参考晶振-后续会放大32 倍 Comparator:比较器,输出RF信号 control logic:控制晶振倍频,控制LF,pow ...

  2. Android程序员学WEB前端(4)-HTML(4)-注册页面-Sublime

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/76576031 觉得博文有用,请点赞,请评论,请关注,谢谢!~ 注册页面1: <! ...

  3. OPEN(SAP) UI5 学习入门系列之一:扫盲与热身(上)

    什么是SAP Fiori? 了解SAP UI5必须要从SAP Fiori开始,两者概念经常被混淆,而两者也确实有着非常紧密的关系. 用过SAP的同学们都对SAP的传统的界面(SAP GUI)表示“呵呵 ...

  4. 文件的copy

    def mycopy(src_filename, dst_filename): try: fr = open(src_filename, "rb") try: try: fw = ...

  5. (android 地图实战开发)2 创建MapActivity,根据设备当前位置,显示地图

    (android 地图实战开发)2 创建MapActivity,根据设备当前位置,显示地图 http://www.cnblogs.com/macroxu-1982/archive/2011/09/13 ...

  6. IE中拖放问题

    1.所有的元素上都能绑定放置目标的事件,但并不保证此元素是有效的放置对象. 默认情况下,IE中只有文本框(<input/>或<textarea/>)是网页上唯一有效的放置目标. ...

  7. for循环使用append问题

    append添加到元素的时候,已存在的元素是移动而不是复制,使用了遍历,所以第一次是新增,后面都是移动前面新增的,最后当然就出现了只有最后一项有东西.解决办法:1.不要遍历,使用jQuery的类选择器 ...

  8. JSP学习(二)JSP指令

    JSP指令 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分. JSP指令的基本语法格式:<%@ 指令 属性名= ...

  9. 为什么 UEFI 方式启动的 U 盘必须使用 FAT32 文件系统?

    如果你希望更刺激地安装 Windows,那么你需要了解很多 Windows 系统相关的问题. 为什么 UEFI 方式启动的 U 盘必须使用 FAT32 文件系统? 因为 NTFS 是 Windows ...

  10. 【知识笔记】VS调试问题

    一.无法在web服务器上启动调试,您没有调试web服务器进程的权限,您需要以web服务器的用户账户身份运行,或者具有管理员权限. 现象:手动修改网站项目的启动端口号,调试报错 原因:从Windows ...