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 条评论
登录 后参与评论

相关文章

来自专栏数据结构与算法

P1807 最长路_NOI导刊2010提高(07)

题目描述 设G为有n个顶点的有向无环图,G中各顶点的编号为1到n,且当为G中的一条边时有i < j。设w(i,j)为边的长度,请设计算法,计算图G中<1,n>间...

2787
来自专栏小樱的经验随笔

HDU 1250 Hat's Fibonacci

Hat's Fibonacci Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32...

34111
来自专栏数据结构与算法

P3385 【模板】负环

题目描述 暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索 输入输出格式 输入格式: 第一行一个正整数T表示数据组数,对于每组数据: 第一行两...

2685
来自专栏Porschev[钟慰]的专栏

一个例子理解C#位移

很多人提问,不知道C#位移,可能有些人在面试中也遇到过 其实很简单。。。 C#位移运算符: 左移:<< 右移:>> 位移理解可能简单一些:其实就是数据转换成二进...

1847
来自专栏算法修养

Code Forces 149DColoring Brackets(区间DP)

 Coloring Brackets time limit per test 2 seconds memory limit per test 256...

2876
来自专栏用户画像

1002. A+B for Polynomials (25)

Each input file contains one test case. Each case occupies 2 lines, and each lin...

744
来自专栏机器学习入门

LWC 56:443. String Compression

LWC 56:443. String Compression 传送门:443. String Compression Problem: Given an ar...

1908
来自专栏机器学习入门

LWC 63:746. Min Cost Climbing Stairs

Problem: On a staircase, the i-th step has some non-negative cost cost[i] assig...

1969
来自专栏ml

HDUOJ-------1753大明A+B(大数之小数加法)

大明A+B Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav...

33612
来自专栏数据结构与算法

浅谈ST表

ST表 ST表的功能很简单 它是解决RMQ问题(区间最值问题)的一种强有力的工具 它可以做到O(nlogn)预处理,O(1)查询最值 算法 ST表是利用的是倍增...

2625

扫码关注云+社区