Java生成随机数(Random和SecureRandom)
随机数在统计分析、概率论、现代计算机模拟和数字密码学等领域具有广泛的应用。开发 Java 程序时,经常会遇到需要使用随机数的场景,如随机验证码、随机测试数据、随机移动路径和密码加密中使用的辅助值等。
Java 提供的 Random 和 SecureRandom 可以作为生成随机数的工具类。
Random 类内部采用伪随机数算法,简单来说就是基于一个种子(long 型值),经过特定的迭代计算得到一个结果,作为产生的随机数。当这个种子是随机数时,产生的结果也是随机数;当这个种子是固定值时,产生的结果也是固定值。
Random 类的构造方法如下表所示。
Random 类中常用的方法如下:
【实例 1】nextInt() 方法的应用。
【实例 2】下面创建 3 个随机数生成器,其中的两个使用相同的种子值 50 创建,最后一个使用种子值 100 创建。
为了保障安全性,Java 提供了 SecureRandom 类。
SecureRandom 类提供了一个加密的强随机数生成器。SecureRandom 类的底层有多种实现,其中一些实现采用伪随机数生成器(Pseudo Random Number Generator,PRNG)的形式,这意味着它们使用确定性算法根据真正的随机种子生成伪随机序列。其他实现可能会产生真正的随机数,有的实现则使用这两种技术的组合形式。当实际使用时,可以优先获取高强度的安全随机数生成器,如果没有提供,就使用普通等级的安全随机数生成器。
SecureRandom 类提供的静态方法 getInstance() 可以用来获取该类的一个对象。常用的 getInstance() 方法有两种:一是仅指定算法名称,二是既指定算法名称又指定提供者名称。
仅指定算法名称:
既指定算法名称又指定提供者名称:
SecureRandom 类中常用的方法如下:
【实例 3】SecureRandom类的基础用法。
声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
Java 提供的 Random 和 SecureRandom 可以作为生成随机数的工具类。
1、Random类
Random 是 java.util 包中的一个类,可以在指定的取值范围内随机产生数字。Random 类内部采用伪随机数算法,简单来说就是基于一个种子(long 型值),经过特定的迭代计算得到一个结果,作为产生的随机数。当这个种子是随机数时,产生的结果也是随机数;当这个种子是固定值时,产生的结果也是固定值。
Random 类的构造方法如下表所示。
方法声明 | 功能描述 |
---|---|
Random() | 创建一个随机数生成器,基于当前系统时间生成种子。 |
Random(long seed) | 创建一个随机数生成器,使用 long 型的 seed 值作为种子,使用相同的 seed 值创建的多个随机数生成器产生的随机数序列相同。 |
Random 类中常用的方法如下:
- nextInt():生成一个 int 型的随机数,该随机数的取值范围与int型的取值范围相同。
- nextInt(int bound):生成一个 int 型的随机数,该随机数的取值范围为 [0,bound),传入的 bound 必须大于 0,否则将抛出异常。
- nextDouble():从该随机数生成器的序列中返回 0.0~1.0 的下一个伪随机且呈均匀分布的双精度值。
- nextGaussian():从该随机数生成器的序列中返回下一个伪随机且呈高斯(“正常”)分布的双精度值,均值为 0.0,标准差为 1.0。
【实例 1】nextInt() 方法的应用。
public class Demo { public static void main(String[] args) { // 创建一个随机数生成器 Random ran = new Random(); // 生成一个int型取值范围内的随机数 System.out.println(ran.nextInt()); // 生成一个10以内的随机数 System.out.println(ran.nextInt(10)); } }运行结果是:
1205200642
9
【实例 2】下面创建 3 个随机数生成器,其中的两个使用相同的种子值 50 创建,最后一个使用种子值 100 创建。
import java.util.*; public class Demo { public static void main(String[] args) { // 创建一个种子值为50的Random对象 Random rl = new Random(50); System.out.println("第一个种子值为50的Random对象"); System.out.println("rl.nextBoolean():\t" + rl.nextBoolean()); System.out.println("rl.nextInt():\t\t" + rl.nextInt()); System.out.println("rl.nextDouble():\t" + rl.nextDouble()); System.out.println("rl.nextGaussian():\t" + rl.nextGaussian()); Random r2 = new Random(50); System.out.println("第二个种子值为50的Random对象"); System.out.println("r2.nextBoolean():\t" + r2.nextBoolean()); System.out.println("r2.nextInt():\t\t" + r2.nextInt()); System.out.println("r2.nextDouble():\t" + r2.nextDouble()); System.out.println("r2.nextGaussian():\t" + r2.nextGaussian()); Random r3 = new Random(100); System.out.println("种子值为100的Random对象"); System.out.println("r3.nextBoolean():\t" + r3.nextBoolean()); System.out.println("r3.nextInt():\t\t" + r3.nextInt()); System.out.println("r3.nextDouble():\t " + r3.nextDouble()); System.out.println("r3.nextGaussian():\t" + r3.nextGaussian()); } }运行结果为:
第一个种子值为50的Random对象 rl.nextBoolean(): true rl.nextInt(): -1727040520 rl.nextDouble(): 0.6141579720626675 rl.nextGaussian(): 2.377650302287946 第二个种子值为50的Random对象 r2.nextBoolean(): true r2.nextInt(): -1727040520 r2.nextDouble(): 0.6141579720626675 r2.nextGaussian(): 2.377650302287946 种子值为100的Random对象 r3.nextBoolean(): true r3.nextInt(): -1139614796 r3.nextDouble(): 0.19497605734770518 r3.nextGaussian(): 0.6762208162903859由运行结果可知,使用相同的种子值创建的随机数生成器生成的随机数序列也是相同的。
2、SecureRandom类
Random 类提供的基于种子的随机数生成器,在种子值已知的情况下生成的随机数序列是可知的,即不再随机,这在安全相关的应用中是非常危险的。例如,如果网站基于该机制生成手机验证码,那么攻击者可以推测出验证码,进而冒充用户登录网站。为了保障安全性,Java 提供了 SecureRandom 类。
SecureRandom 类提供了一个加密的强随机数生成器。SecureRandom 类的底层有多种实现,其中一些实现采用伪随机数生成器(Pseudo Random Number Generator,PRNG)的形式,这意味着它们使用确定性算法根据真正的随机种子生成伪随机序列。其他实现可能会产生真正的随机数,有的实现则使用这两种技术的组合形式。当实际使用时,可以优先获取高强度的安全随机数生成器,如果没有提供,就使用普通等级的安全随机数生成器。
SecureRandom 类提供的静态方法 getInstance() 可以用来获取该类的一个对象。常用的 getInstance() 方法有两种:一是仅指定算法名称,二是既指定算法名称又指定提供者名称。
仅指定算法名称:
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");系统将确定环境中是否有所请求的算法实现,是否有多个,以及是否有首选实现。
既指定算法名称又指定提供者名称:
SecureRandom random = SecureRandom.getInstance("SHA1PRNG","SUN");系统将确定在所请求的包中是否有算法实现,若没有则抛出异常。
SecureRandom 类中常用的方法如下:
- setSeed(byte[] seed):重新设置当前随机数生成器的种子,需要注意的是,该方法使用传入的seed值补充原有的种子,而非代替,因此,调用该方法并不会降低随机性。
- nextBytes(byte[] bytes):生成用户指定数量的随机字节。
- generateSeed(int numBytes):返回指定数量的种子字节,调用该方法可以为当前随机数生成器和其他随机数生成器提供种子。
【实例 3】SecureRandom类的基础用法。
import java.security.SecureRandom; public class Demo { public static void main(String[] args) { // 创建一个SecureRandom实例 SecureRandom secureRandom = new SecureRandom(); // 生成指定数量的随机字节,并打印出来 byte[] randomBytes = new byte[16]; // 假设我们想要16个字节的随机数据 secureRandom.nextBytes(randomBytes); System.out.println("生成的随机字节: " + bytesToHex(randomBytes)); // 使用generateSeed生成种子,并设置到SecureRandom实例 byte[] seed = secureRandom.generateSeed(8); // 生成8个字节的种子 secureRandom.setSeed(seed); // 设置种子,这将补充而非替代原有的种子 // 再次生成随机字节,这次使用了新的种子 secureRandom.nextBytes(randomBytes); System.out.println("使用新种子生成的随机字节: " + bytesToHex(randomBytes)); } // 辅助方法,将字节转换为十六进制字符串 private static String bytesToHex(byte[] bytes) { StringBuilder hexString = new StringBuilder(); for (byte b : bytes) { String hex = Integer.toHexString(0xff & b); if (hex.length() == 1) { hexString.append('0'); } hexString.append(hex); } return hexString.toString(); } }运行结果为:
生成的随机字节: 6ef49573b9eb0a98d635057d28461bef
使用新种子生成的随机字节: d22fc62f5f63a87318bc2baf80d45e1d
声明:《Java系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。