Java 解惑:Random 种子的作用、含参与不含参构造函数区别

Random 通常用来作为随机数生成器,它有两个构造方法:

        Random random = new Random();
        Random random2 = new Random(50);

1.不含参构造方法:

public Random() {
    setSeed(System.nanoTime() + seedBase);
    ++seedBase;
}

2.含参构造方法:

public Random(long seed) {
    setSeed(seed);
}

都调用的 setSeed 方法:

public synchronized void setSeed(long seed) {
    this.seed = (seed ^ multiplier) & ((1L << 48) - 1);
    haveNextNextGaussian = false;
}

可以看到,不含参构造方法每次都使用当前时间作为种子,而含参构造方法是以一个固定值作为种子

什么是种子 seed 呢?

seed 是 Random 生成随机数时使用的参数:

Random 中最重要的就是 next(int) 方法,使用 seed 进行计算:

protected synchronized int next(int bits) {
    seed = (seed * multiplier + 0xbL) & ((1L << 48) - 1);
    return (int) (seed >>> (48 - bits));
}

其他 nextXXX 方法都是调用的 next()。

比如 nextInt(int):

public int nextInt(int n) {
    if (n <= 0) {
        throw new IllegalArgumentException("n <= 0: " + n);
    }
    if ((n & -n) == n) {
        //调用 next()
        return (int) ((n * (long) next(31)) >> 31);
    }
    int bits, val;
    do {
        bits = next(31);
        val = bits % n;
    } while (bits - val + (n - 1) < 0);
    return val;
}

再比如 nextBoolean():

//也是调用的 next()
public boolean nextBoolean() {
    return next(1) != 0;
}

举个栗子:

@Test
public void testRandomParameter(){
    System.out.println("Random 不含参构造方法:");
    for (int i = 0; i < 5; i++) {
        Random random = new Random();
        for (int j = 0; j < 8; j++) {
            System.out.print(" " + random.nextInt(100) + ", ");
        }

        System.out.println("");
    }

    System.out.println("");

    System.out.println("Random 含参构造方法:");
    for (int i = 0; i < 5; i++) {
        Random random = new Random(50);
        for (int j = 0; j < 8; j++) {
            System.out.print(" " + random.nextInt(100) + ", ");
        }
        System.out.println("");
    }
}

分别用含参构造方法和不含参构造方法创建 5 个随机生成器对象,每个随机生成器再生产 8 个随机数,对比下结果:

再运行一次:

总结:

通过上述例子可以发现:

随机数是种子经过计算生成的

  • 不含参的构造函数每次都使用当前时间作为种子,随机性更强
  • 而含参的构造函数其实是伪随机,更有可预见性

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏工科狗和生物喵

【计算机本科补全计划】《C++ Primer》:表达式以及运算符

正文之前 好久没写了啊!!感觉自己都已经不爱简书了。不过其实我的《C++ Primer》已经看到400多页了。然而网络笔记还停留在120页,这个很骚啊,意味着我...

3317
来自专栏noteless

[三]基础数据类型之Integer详解

693
来自专栏大数据学习笔记

面试算法题

题目来源于牛客网:https://www.nowcoder.com/ta/coding-interviews 1、二维数组中的查找 在一个二维数组中,每一行都按...

7786
来自专栏鬼谷君

python判断字符串,str函数isdigit、isdecimal、isnumeric的区别

962
来自专栏菜鸟计划

javascript 面向对象(实现继承的几种方式)

 1、原型链继承 核心: 将父类的实例作为子类的原型 缺点: 父类新增原型方法/原型属性,子类都能访问到,父类一变其它的都变了 function...

3258
来自专栏mathor

JAVA——基本数据类型

944
来自专栏C/C++基础

OpenMP并行加速笛卡尔乘积

问题描述: 对于给定的由字典字符集组合而成的表达式,求该表达式构成的所有元素。例如表达式[0-9][a-z],其中0-9表示10个数字,a-z表示26个小写...

792
来自专栏杨建荣的学习笔记

关于oracle中的sql数据类型(r3笔记第59天)

数据类型对于每一种编程语言而言都是数据存储的基础,对于编程语言的实现功能而言也是一个标尺,有些编程语言可能数据类型很丰富,比如java,c,在数据计算方面的支持...

2604
来自专栏Linyb极客之路

Java中final和static关键字总结

final修饰的类不可被继承,例如java.lang.Math就是一个 final类,不可被继承。

733
来自专栏程序员互动联盟

【编程基础】c printf知多少

printf()函数是格式输出函数,请求printf()打印变量的指令取决与变量的类型.例如,在打印整数是使用%d符号,在打印字符是用%c 符号.这些符号被称为...

3285

扫码关注云+社区