查看原文
其他

Java中Math.random()与Random类生成随机数及源码分析

素文宅博客 Java精选 2022-08-09

点击上方蓝色“Java精选”,选择“设为星标”

技术文章第一时间送达!

Math.random()是生成随机选取大于等于0且小于1的伪随机数,也就是说,从0(包含0)往上且不包括1(去除1)的所有范围。

Random类包含有参数和无参数的构造方法,其中无参数的构造方法每次都是使用当前系统时间作为种子,而有参数的构造方法是使用一个固定值(参数)作为种子。每次使用时先创建一个Random对象,称为随机数生成器,然后调用Random.next**()方法获取数值。

Math.random()方法生成随机数

生成一个[0,1)之间的随机数,举例参考代码如下:
package com.yoodb.study.other.random;

public class DemoTest01 {
public static void main(String[]args){
System.out.println("通过Math.random产生的随机数列[关注微信公众号“Java精选”]:");
for (int j = 0; j < 8; j++) {
System.out.print(Math.random() + ",");
}
}
}
运行结果如下:
通过Math.random产生的随机数列[关注微信公众号“Java精选”]:
0.5956019878671859,0.24739500123720504,0.09675226363769507,0.11460305663401749,0.7565292415953803,0.13633278295115547,0.7136188381381711,0.9789645131075377,
生成一个8位的随机整数,参考代码如下:
package com.yoodb.study.other.random;

public class DemoTest02 {
public static void main(String[]args){
int rand = (int)(Math.random()*100000000);
System.out.println("生成一个8位的随机整数为:" + rand);
}
}
运行结果如下:
生成一个8位的随机整数为:11891302

Random类生成随机数

有参数构造方法:随机数生成器即Random对象,种子的值100。生成[0-n)的数值,也就是包括0,但是不包括n且全都是整数,代码如下:
package com.yoodb.study.other.random;

import java.util.Random;

public class DemoTest03 {
public static void main(String[]args){
for(int i = 0; i < 2; i++){
System.out.println("执行第" + (i+1) + "次");
Random random = new Random(100);
for(int j = 0; j < 3; j++) {
System.out.println("生成[0-50)的整数值为:" + random.nextInt(50));
}
}
}
}
运行结果如下:
执行第1次
生成[0-50)的整数值为:15
生成[0-50)的整数值为:0
生成[0-50)的整数值为:24
执行第2次
生成[0-50)的整数值为:15
生成[0-50)的整数值为:0
生成[0-50)的整数值为:24
注:当使用有参数的构造创建随机数生成器然后生成随机数序列时,产生的随机数是经过传递的参数计算得到的,具有相同参数的Random对象生成的随机数序列相同。
无参数构造方法:随机数生成器即Random对象,不传递种子。生成[0-n)的数值,也就是包括0,但是不包括n且全都是整数,代码如下:
package com.yoodb.study.other.random;

import java.util.Random;

public class DemoTest03 {
public static void main(String[]args){
for(int i = 0; i < 2; i++){
System.out.println("执行第" + (i+1) + "次");
Random random = new Random();
for(int j = 0; j < 3; j++) {
System.out.println("生成[0-50)的整数值为:" + random.nextInt(50));
}
}
}
}
运行结果如下:
执行第1次
生成[0-50)的整数值为:44
生成[0-50)的整数值为:45
生成[0-50)的整数值为:38
执行第2次
生成[0-50)的整数值为:40
生成[0-50)的整数值为:34
生成[0-50)的整数值为:14
注:通过无参构造创建Random对象,其本质是也是种子,只不过种子不是具体的数值,而是系统当前的时间,也因此创建的随机数是不相同的。

Random类源码分析

关于Random类,其构造方法源码如下:
/**
* 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.
*/
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
译:创建新的随机数生成器。此构造方法设置随机数生成器的种子是一个值与此构造方法的任何其他调用不同。
点击this,跳转到对应的有参构造中,显然由代码可以看出种子的生成和当前时间有关系,因此这样生成的种子是唯一的。
public Random(long seed) {
if (getClass() == Random.class)
this.seed = new AtomicLong(initialScramble(seed));
else {
// subclass might have overriden setSeed
this.seed = new AtomicLong();
setSeed(seed);
}
}

Math.random()和Random类两者关系

查看Math类源码,具体如下:
...
private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}
...
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}
...
从Math类的源码分析可以看出Math.random()方法内部调用的方法就是Random类中的nextDouble()方法,此时可以看出Math.random()返回的是double类型值。
通过比较可以得出结论:
1、随机数是种子经过计算生成的。
2、Random类中不含参的构造方法每次都是使用当前时间作为种子,随机性强;而含有参数的构造方法是以参数为种子产生的伪随机数,更有可预见性。
3、具有相同种子值的Random对象生成的随机数相同;种子值不同,产生的随机数不再一致。
4、Math.random()方法中内部调用的方法是Random类中的nextDouble()方法。
关注我,回复“Java”免费领取视频教程和资料

回复“加群”加入专业技术讨论群^^

往期精选

最新IntelliJ IDEA 2019.3版本永久激活,一步到位!

BAT等公司必问的8道Java经典面试题,你都会了吗?

深入理解 Spring AOP XML 配置方式实现原理源码剖析

Eclipse中使用Git插件如何将代码提交至远程仓库

深入理解 Spring AOP 注解方式实现原理源码剖析深入理解 

Spring 事务底层实现原理,通俗易懂

Java开发中常见路径问题的分析及解决方法,你会如何解决?

Eclipse应该向IntelliJ IDEA学习的5种优秀特性

Eclipse黑色主题插件居然可以这么玩,真是玩出了新高度!

我就知道你“在看”!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存