Java:(new Random())。nextInt(5)总是返回相同的数字吗?

Java: Can (new Random()).nextInt(5) always return the same number?

有时这段代码总是返回相同的数字(有时效果很好):

1
(new Random()).nextInt(5)

我怀疑问题出在哪里-它可能总是用相同的种子创建一个新的Random。 那么什么是最好的解决方案:

  • 为Random()创建一个静态变量,并
    改用它。
  • 使用Math.random()* 5
    (看起来它使用了静态变量
    内部)

或者是其他东西? 我不需要花哨的东西,只是看起来很随意的东西。

如果有人可以解释为什么原始代码有时有效而有时无效的话,这也将有所帮助。

谢谢。


java.util.Random的javadoc很清楚:

If two instances of Random are created
with the same seed, and the same
sequence of method calls is made for
each, they will generate and return
identical sequences of numbers.

默认构造函数也很清楚:

Creates a new random number generator.
This constructor sets the seed of the
random number generator to a value
very likely to be distinct from any
other invocation of this constructor.

换句话说,没有保证。

如果需要更随机的算法,请使用java.security.SecureRandom。


如果要在连续的代码行上调用该代码行,那么可以,您正在创建的两个Random实例可以使用相同的种子时钟来创建(时钟毫秒滴答计数是Random对象的默认种子)。几乎普遍来说,如果应用程序需要多个随机数,则可以创建一个Random实例,然后根据需要重复使用它。

编辑:有趣的是,自1.4.2起,用于Random的javadoc发生了变化,这说明时钟已用作默认种子。显然,这不再是保证。

编辑#2:顺便说一句,即使您重复使用正确播种的Random实例,在调用nextInt(5)的时间的大约1/5时,您仍将获得与上一次调用相同的随机数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static void main(String[] args) {
    Random rand = new Random();
    int count = 0;
    int trials = 10000;

    int current;
    int previous = rand.nextInt(5);

    for(int i=0; i < trials; ++i)
    {
        current = rand.nextInt(5);

        if( current == previous )
        {
            count++;
        }
    }

    System.out.println("Random int was the same as previous" + count +
                      " times out of" + trials +" tries.");
}


...Sometimes this piece of code [..] returns the same number (and sometimes it works fine)...

所以它随机工作??? :) :) :)

好吧,好吧,现在就对我投反对票!


在Java 1.4中,API文档中将新Random实例的默认种子指定为System.currentTimeMillis()的结果。显然,一个紧密的循环可以在每个刻度上创建许多Random()实例,所有实例都具有相同的种子,并且都产生相同的伪随机序列。这在某些时钟分辨率较差(10毫秒或更高)的平台(例如Windows)上尤其糟糕。

但是,从Java 5开始,每次默认构造函数的调用都将种子设置为"很可能是不同的值"。对于每个Random实例,使用不同的种子,结果应根据需要随机出现。


近似均匀分布的最佳方法是使用静态方法Random.nextInt(n)产生[0,n-1]范围内的整数(是,n被排除)。在您的特定示例中,如果希望整数在0到5之间(包括0和5),则应调用Random.nextInt(6)。


用于Random的Javadoc对此并不明确,但是它使用的种子可能取决于当前系统时间。它确实声明随机数对于相同的种子将是相同的。如果您在同一毫秒内使用该调用,它将使用相同的种子。最好的解决方案可能是使用静态的Random对象,并将其用于随后的方法调用。