java.util.Collections.shuffle 平台是不是依赖?
Posted
技术标签:
【中文标题】java.util.Collections.shuffle 平台是不是依赖?【英文标题】:Is java.util.Collections.shuffle platform dependent?java.util.Collections.shuffle 平台是否依赖? 【发布时间】:2019-01-12 21:49:52 【问题描述】:我们需要使用种子对 ArrayList 进行洗牌
代码是这样的:
List<String> tempList = new ArrayList<>()
//code to populdate the tempList
Random rng = new Random(2018);
Collections.shuffle(tempList, rng);
附:我们提供静态随机种子的原因是为了确保它在洗牌后始终产生相同的结果。
我们观察到的是,开发机器 (Mac) 上的洗牌结果与我们的构建机器 (Linux) 上的洗牌结果不同
我想知道这个方法本身是否依赖于平台?
JDK 详细信息 Mac 已开启:
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)
构建机器(我需要更多时间来了解更多详细信息,因为我无权访问):
jdk1.8.0_162
【问题讨论】:
您是否使用不同的 JVM?还是甲骨文(Hotspot)的官方?哪个版本?您能否提供有关测试设置和机器的更多信息?Random
对象本身呢?尝试使用nextInt
生成一些数字,看看序列是否也不同。
在不同的JVM上会不会不一样?我会找出版本详细信息并更新问题
可预测的改组的目的是什么?
它需要被洗牌,所以列表不是按字母顺序排列的。它需要可预测的原因是它在开发机器和构建机器上是相同的打乱顺序。
应该没有变化,即使 Java 版本不同。来自the docs:“为了保证这个属性,为类 Random 指定了特定的算法。为了 Java 代码的绝对可移植性,Java 实现必须使用此处为类 Random 显示的所有算法。”
【参考方案1】:
据我了解,您是在问这个 Java 程序是否保证在现有的每个 Java 实现上打印 bcdea
。
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
class Main
public static void main(String[] args)
Random rng = new Random(42);
ArrayList<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
Collections.shuffle(list, rng);
for (String s : list) System.out.print(s);
;
tio.run says 至少在“OpenJDK 8”和它们称为“JDK”的任何东西之间产生相同的输出。但这是一个非常小而无聊的样本。
The official Oracle docs 不放心:
使用指定的随机源随机排列指定的列表。假设随机性来源是公平的,所有排列的发生可能性均等。
此实现向后遍历列表,从最后一个元素到第二个元素,反复将随机选择的元素交换到“当前位置”。元素是从列表中从第一个元素到当前位置(含)的部分中随机选择的。 [强调添加。]
也就是说,Oracle 并没有声称每个 实现都以这种方式工作;他们甚至也懒得去记录交换的元素是如何“随机选择”的。
顺便说一句,在看到 Collections.shuffle
使用 in U.S. voting system software 后,我提出了您的问题,并且正是基于这样的假设:无论您使用什么 JDK,它的行为都是可重现的。我同意完全不清楚是否是这种情况。
(顺便说一句,C++ std::shuffle
不是这种情况。不同的库实现 can and do 为相同的输入提供不同的随机播放。)
【讨论】:
以上是关于java.util.Collections.shuffle 平台是不是依赖?的主要内容,如果未能解决你的问题,请参考以下文章