为什么Random类不是静态的?

26

在Java中,我们有静态类Math。你不需要创建它的对象,因此它是静态的。另一个是Random类。我们不需要创建它的实例,那么为什么它不是静态的呢?我经常使用随机数,并且在每个类中创建rand字段以生成随机数时感到很烦恼。那为什么不把它设为静态的呢?


9
Java中的顶层类不能声明为静态,你确实需要创建Random的实例。你提出问题时的前提都是不正确的。 - Jon Skeet
在 Math 中有一个静态的 random()。 - josefx
一个更好的问题应该是:“为什么Random类不是final的?” - bvdb
4个回答

32

Random类有状态,包括它在序列中的位置,因为生成的值并不是真正的随机值,而只是伪随机序列。

可以通过使用相同的种子初始化两个实例来证明这一点。

Random a = new Random(123);
Random b = new Random(123);
for (int i = 0; i < 5; i++) {
    System.out.println(a.nextInt() + "," + b.nextInt());
}

输出

-1188957731,-1188957731
1018954901,1018954901
-39088943,-39088943
1295249578,1295249578
1087885590,1087885590

如果您使用默认构造函数Random()创建对象,则种子基于当前纳秒时间加上静态计数器进行初始化,这意味着不同的实例很可能具有不同的随机序列。


2
如果您使用默认构造函数Random()创建,则种子将用当前毫秒数初始化。但是,即使对于默认的new Random(),种子的生成也比仅使用System.currentTimeMillis()更为复杂。 - bestsss
@bestsss 抱歉,你是正确的。我在查看一些非常古老的java.util.Random源代码(令人恼火的是谷歌上排名第一)。在1.5版本之前,使用System.currentTimeMillis()曾经是预期的行为,但现在如你所说,已经更加复杂化了。 - Adam
是的,在1.5中进行了更改,它确实只有毫秒(相当糟糕)。 - bestsss

14

确实需要创建实例,因为随机数生成器有状态。具体来说,该状态控制伪随机序列中的当前位置。

如果您想要多个独立的生成器(不共享状态),那么您需要单独的实例。


5
原因在于您可能需要多个独立的随机数生成器,这可以通过拥有多个Random实例来实现。

5

关键在于种子。正如您所知,我们不讨论真正的随机数,而是伪随机数。当您知道第一个数字时,您可以计算出其他数字。这就是为什么我们使用所谓的“种子”的原因。每个Random对象都有不同的种子。如果Random是静态的,您将无法拥有两个不同的种子。请注意,setSeed()方法将影响所有随机数生成器(而我们经常只想更改一个)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接