原创

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

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精选”(w_z90110),回复关键词领取资料:如Mysql、Hadoop、Dubbo、Spring Boot等,免费领取视频教程、资料文档和项目源码。

Java精选专注程序员推送一些Java开发知识,包括基础知识、各大流行框架(Mybatis、Spring、Spring Boot等)、大数据技术(Storm、Hadoop、MapReduce、Spark等)、数据库(Mysql、Oracle、NoSQL等)、算法与数据结构、面试专题、面试技巧经验、职业规划以及优质开源项目等。其中一部分由小编总结整理,另一部分来源于网络上优质资源,希望对大家的学习和工作有所帮助。

评论

分享:

支付宝

微信