首页 > 编程语言 >【java开发】Java随机数的种子

【java开发】Java随机数的种子

时间:2024-11-19 13:41:58浏览次数:1  
标签:java Random System 随机 随机数 Java SecureRandom 种子

在许多领域,比如模拟、游戏和密码学中,随机数担任非常重要的角色。

然而,在计算机领域,随机数并非完全随机,它们是由模拟随机性的算法(称为伪随机性)生成的。

在Java中,随机种子就是初始化伪随机数生成器(PRNG,Pseudo Random Number Generator)的值。

我们一起探讨下,Java中随机种子的工作原理,以及如何使用它生成可预测的数字序列。

一、什么是随机种子?

随机种子是设置PRNG(伪随机数生成器)内部状态的初始值。

默认情况下,如果我们指定种子值,Java的Random类会使用系统时钟作为种子值。这样做的好处是,确保了每次创建新的Random对象时,生成的数字序列都是不同的,增加了随机性。

如果我们提供特定的种子值,每次都会生成相同的“随机”数字序列。这在我们需要可重复性的情况下非常有用,比如测试、调试或需要结果一致性的模拟场景。

有了种子值之后,PRNG算法会基于种子值生成一系列数字。

每次我们调用nextInt()、nextDouble()或类似方法时,它都会更新生成器的内部状态,从而保证每次生成一个新数字。但是,如果使用相同的种子,生成的数字序列将始终相同。

接下来我们看下这两种情况。

二、不使用种子生成随机数

Java提供了java.util.Random类,用于生成随机数。

当我们创建一个Random实例而不指定种子时,Java会使用系统时钟为生成器设定种子。这意味着每次运行都会产生不同的序列。例如:

import java.util.Random;

public class RandomWithoutSeed {
    public static void main(String[] args) {
        Random random = new Random();
        // 生成7个随机整数
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random.nextInt(100)); // 0到99之间的随机整数
        }
        System.out.println();

        Random random2 = new Random();
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random2.nextInt(100)); // 0到99之间的随机整数
        }
        System.out.println();

        Random random3 = new Random();
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random3.nextInt(100)); // 0到99之间的随机整数
        }
    }
}

在这个例子中,每次运行都会生成不同的随机整数序列,因为种子是根据当前时间自动设置的。

第一次运行结果是:

76 	9 	11 	77 	67 	91 	91
76 	44 	28 	5 	91 	59 	30
41 	18 	72 	14 	6 	4 	63

在运行一次:

33 	65 	97 	31 	94 	19 	1
97 	2 	40 	58 	9 	33 	57
46 	82 	21 	94 	54 	36 	79

可以看出来,结果基本上符合随机性。(上面的结果只是展示下随机效果,每次运行都会有差异)

三、使用种子生成随机数

当我们提供特定的种子时,生成的数字序列在不同的运行中是可预测且一致的。

import java.util.Random;

public class RandomWithSeed {
    public static void main(String[] args) {
        Random random = new Random(12345L); // 种子设置为12345
        // 生成7个随机整数
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random.nextInt(100)); // 0到99之间的随机整数
        }
        System.out.println();

        Random random2 = new Random(12345L); // 种子设置为12345
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random2.nextInt(100)); // 0到99之间的随机整数
        }
        System.out.println();

        Random random3 = new Random(12345L); // 种子设置为12345
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random3.nextInt(100)); // 0到99之间的随机整数
        }
    }
}

在这里,Random类的构造函数接受一个种子值作为参数,在这个例子中,种子被设置为12345L(一个特定的长整型值)。

这个种子初始化伪随机数生成器(PRNG),重要的是,它确保如果程序使用相同的种子运行,将始终生成相同的数字序列。

第一次运行结果是:

51 	80 	41 	28 	55 	84 	75
51 	80 	41 	28 	55 	84 	75
51 	80 	41 	28 	55 	84 	75

再来一次还是这样:

51 	80 	41 	28 	55 	84 	75
51 	80 	41 	28 	55 	84 	75
51 	80 	41 	28 	55 	84 	75

所以说,“随机”是可以操纵的。

四、使用SecureRandom

在密码学应用中,使用可预测的随机数可能会导致安全漏洞。

Java提供了SecureRandom类用于生成密码学安全的随机数。

看名字就知道,SecureRandom安全等级高一些。


import java.security.SecureRandom;

public class SecureRandomExample {
    public static void main(String[] args) throws Exception {
        SecureRandom random = new SecureRandom(new byte[] {1, 2, 3, 4, 5});
        // 生成7个随机整数
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random.nextInt(100)); // 0到99之间的随机整数
        }
        System.out.println();

        SecureRandom random2 = new SecureRandom(new byte[] {1, 2, 3, 4, 5});
        // 生成7个随机整数
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random2.nextInt(100)); // 0到99之间的随机整数
        }
        System.out.println();

        SecureRandom random3 = new SecureRandom(new byte[] {1, 2, 3, 4, 5});
        // 生成7个随机整数
        for (int i = 0; i < 7; i++) {
            System.out.format("%d \t", random3.nextInt(100)); // 0到99之间的随机整数
        }
    }
}

上面的例子中,我们传入相同的种子,运行结果也是随机的。

第一次运行:

78 	68 	56 	24 	73 	13 	88
24 	14 	20 	69 	25 	4 	61
25 	8 	32 	39 	25 	16 	87

第二次运行:


4 	35 	46 	26 	48 	92 	66
83 	92 	28 	64 	13 	75 	44
60 	79 	81 	52 	7 	66 	11

结果也是足够随机的。(上面的结果只是展示下随机效果,每次运行都会有差异)

SecureRandom使用高熵值的源来初始化其内部状态。熵是对不确定性或随机性的度量,高熵源意味着具有更多的随机性。
常见的熵源包括:

操作系统提供的随机数据:许多操作系统都有内置的随机数生成器,它们从硬件设备(如鼠标移动、键盘敲击时间间隔、磁盘 I/O 操作等)收集随机事件产生的数据,这些数据具有较高的随机性,SecureRandom可以从中获取种子或随机数据来初始化自身。
硬件随机数生成器:某些计算机系统配备了专门的硬件设备来生成真正的随机数,例如基于热噪声、放射性衰变等物理现象的硬件随机数生成器。这些硬件设备能够产生高质量的随机数,SecureRandom可以直接使用或结合这些硬件生成的随机数来增强随机性。

SecureRandom会维护一个内部状态,该状态在每次生成随机数时都会更新。新生成的随机数不仅取决于当前的熵源数据,还与之前的内部状态有关。这种状态更新机制使得生成的随机数序列更加难以预测,即使攻击者获取了部分随机数,也难以推断出后续的随机数。

与普通的Random类不同,SecureRandom对种子的管理更为严格。它可以自动从可靠的熵源获取种子,以确保每次初始化时都有足够的随机性。

虽然允许用户提供种子,但通常建议让系统自动管理种子,以充分利用高质量的熵源。

需要注意的是,假设在一个非常空闲的机器上,SecureRandom使用高熵值可能会使服务卡死,机器没有足够的随机信息,SecureRandom无法生成种子,就难以运行了。

总结

在本文中,我们一起探讨了Java中随机种子的工作原理,以及它如何影响伪随机数的生成。

原创 看山的小屋

标签:java,Random,System,随机,随机数,Java,SecureRandom,种子
From: https://www.cnblogs.com/o-O-oO/p/18554341

相关文章

  • Java与大数据:二本硕士的最佳职业发展路径
    在当前激烈的就业环境下,二本院校的硕士生常常会陷入迷茫-是专注Java开发,还是投身大数据领域?经过多年的行业观察和实践,我想分享一个明确的答案:以Java为根基,再拓展大数据技术,这是一条稳健且高效的发展路径。作为亲历者和观察者,我看到太多求职者在技术选择上走了弯路。有的同学......
  • Javaweb核⼼之转发-重定向
    【⾯面试必备】请求转发RequestDispatcher你知道多少简介:讲解请求转发RequestDispatcher的知识点什么是请求转发:request.getRequestDispatcher(URL地址).forward(request,response)客户端发送请求,Servlet做出业务逻辑处理理。Servlet调⽤用forword()⽅方法,服务器器Servlet把⽬标......
  • [Java] 浮点数的精度丢失问题与精度控制方法
    1需求描述场景1:两个整型相除,如何保证运算结果为浮点数?如何控制运算结果的精度(小数位数)?场景2:针对一个浮点数,如何控制其精度(小数位数)?2试验场景:两整型数相除,控制运算结果、浮点数的精度Longnumber1=110600L;intnumber2=999;intscale=2;//精度n(保留n位小数)/......
  • 记录个Java/Groovy的小问题:空字符串调用split函数返回非空数组
    问题复现最近写了一个groovy替换程序增量流水线脚本(会Java也能看懂),示意脚本如下://获取文件列表方法deflistFiles(folder){defoutput=sh(script:"ls${folder}",returnStdout:true).trim()returnoutput.split('\n')asList}//调用以上方法获取lib目录下......
  • JAVA反序列化学习-CommonsCollections3(基于ysoserial)
    环境准备JDK1.7(7u80)、commons-collections(3.x4.x均可这里使用3.2版本)JDK:https://repo.huaweicloud.com/java/jdk/7u80-b15/jdk-7u80-windows-x64.exe<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</a......
  • 《探索 Java 代码的魅力》
    在编程的世界里,Java无疑是一颗璀璨的明星。它以其强大的功能、跨平台性和广泛的应用场景,成为了众多开发者的首选语言。一、Java的历史与发展Java诞生于1995年,由SunMicrosystems公司推出。它的设计初衷是为了开发一种可以在各种不同的设备上运行的编程语言,以实现“......
  • 《深入理解 Java 类》
    在Java编程中,类(Class)是构建程序的基本单元。它封装了数据和操作这些数据的方法,为代码的组织和复用提供了强大的机制。一、Java类的定义一个Java类通常由以下几个部分组成:类声明:使用关键字“class”来声明一个类,后面跟着类名。例如:classMyClass{}。成员变量:也称......
  • Java 框架:强大的开发利器
    在当今的软件开发领域,Java一直以其强大的性能、跨平台性和丰富的生态系统而备受青睐。而Java框架更是在开发过程中发挥着至关重要的作用,它们为开发者提供了高效、可维护和可扩展的开发方式。一、什么是Java框架?Java框架是一种预先编写好的代码库和工具集合,旨在帮助......
  • JAVA 继承:代码复用与功能扩展的强大机制
    在Java编程中,继承是一种非常重要的概念,它为代码复用和功能扩展提供了强大的机制。本文将深入探讨Java继承的概念、用法以及其带来的好处。一、什么是Java继承?继承是面向对象编程中的一个重要概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以扩展父类的......
  • java_1
    目录学习内容:一:变量,数据类型,运算符1.变量 2.数据类型数据类型详解:3.常量 4.运算符算数运算符:关系运算符: 位运算符:逻辑运算符:  赋值运算符: 5.Java运算符优先级: 6.Scanner的用法学习内容:一:变量,数据类型,运算符1.变量变量:变量可以变化,是放在内存中运行......