杰瑞科技汇

Java random 随机数如何正确使用?

在 Java 中,主要有三种方式来生成随机数,它们分别用于不同的场景:

  1. java.lang.Math.random():最简单、最基础的方法,用于生成 [0.0, 1.0) 区间的 double 类型随机数。
  2. java.util.Random:功能更全面的类,可以生成各种基本类型的随机数,并且可以设置随机数种子。
  3. java.security.SecureRandom:用于生成高强度的、密码学安全的随机数,适用于安全敏感的场景(如生成验证码、密钥等)。

java.lang.Math.random()

这是最简单、最直接的方式,无需创建任何对象。

特点:

  • 类型:返回一个 double 类型的值。
  • 范围:返回的值是一个大于等于 0.0 且小于 1.0 的伪随机浮点数 ([0.0, 1.0))。
  • 使用:静态方法,直接通过 Math.random() 调用。

如何生成特定范围的整数?

这是 Math.random() 最常见的用法,其核心公式是:

// 生成 [min, max] 区间内的随机整数
(int)(Math.random() * (max - min + 1)) + min

公式解析:

  1. Math.random():生成 [0.0, 1.0) 的随机数。
  2. * (max - min + 1):将范围扩大到 [0.0, max - min + 1),要生成 1-10 的随机数,max - min + 1 10 - 1 + 1 = 10,范围变为 [0.0, 10.0)
  3. (int):强制类型转换,会截断小数部分,得到 [0, max - min] 的整数。[0.0, 10.0) 转换后是 [0, 9]
  4. + min:将整个范围向右平移 min 个单位,最终得到 [min, max] 的整数。

示例代码:

public class MathRandomExample {
    public static void main(String[] args) {
        // 1. 生成 [0.0, 1.0) 的随机 double
        double randomDouble = Math.random();
        System.out.println("随机 double: " + randomDouble);
        // 2. 生成 [1, 10] 范围内的随机整数
        int randomInt1to10 = (int)(Math.random() * 10) + 1;
        System.out.println("1到10的随机整数: " + randomInt1to10);
        // 3. 生成 [50, 100] 范围内的随机整数
        int randomInt50to100 = (int)(Math.random() * 51) + 50; // 100 - 50 + 1 = 51
        System.out.println("50到100的随机整数: " + randomInt50to100);
        // 4. 生成 [-10, 10] 范围内的随机整数
        int randomIntMinus10to10 = (int)(Math.random() * 21) - 10; // 10 - (-10) + 1 = 21
        System.out.println("-10到10的随机整数: " + randomIntMinus10to10);
    }
}

适用场景:当只需要快速生成一个简单的、非密码学相关的随机数时,非常方便。


java.util.Random

Random 类提供了更强大和灵活的随机数生成功能。

特点:

  • 类型:可以生成 int, long, double, float, boolean 等多种类型的随机数。
  • 范围
    • nextInt(): Integer.MIN_VALUEInteger.MAX_VALUE
    • nextInt(int bound): [0, bound) (左闭右开)
    • nextDouble(): [0.0, 1.0)
  • 使用:需要先创建 Random 对象,然后调用其方法。

示例代码:

import java.util.Random;
public class UtilRandomExample {
    public static void main(String[] args) {
        // 创建一个 Random 对象
        Random rand = new Random();
        // 1. 生成一个随机的 int (范围非常大)
        int randomInt = rand.nextInt();
        System.out.println("随机 int: " + randomInt);
        // 2. 生成 [0, 10) 范围内的随机整数 (即 0-9)
        // 这比用 Math.random() 更直观!
        int randomInt0to9 = rand.nextInt(10);
        System.out.println("0到9的随机整数: " + randomInt0to9);
        // 3. 生成 [1, 10] 范围内的随机整数
        // 先生成 [0, 10) 的数,然后加 1
        int randomInt1to10_v2 = rand.nextInt(10) + 1;
        System.out.println("1到10的随机整数 (v2): " + randomInt1to10_v2);
        // 4. 生成随机的 long
        long randomLong = rand.nextLong();
        System.out.println("随机 long: " + randomLong);
        // 5. 生成随机的 boolean
        boolean randomBoolean = rand.nextBoolean();
        System.out.println("随机 boolean: " + randomBoolean);
        // 6. 生成随机的 double
        double randomDouble = rand.nextDouble();
        System.out.println("随机 double: " + randomDouble);
    }
}

设置随机数种子

Random 类的构造函数可以接受一个 long 类型的种子。

// 使用固定种子 123 创建 Random 对象
Random seededRandom = new Random(123);
// 无论运行多少次,下面这行代码输出的结果永远是一样的
System.out.println(seededRandom.nextInt(100)); // 第一次输出总是 62

种子的作用:伪随机数生成器(PRNG)从一个初始值(种子)开始,通过固定的算法计算出后续的“随机”数,如果种子相同,整个随机数序列也完全相同。

用途

  • 可复现性:在测试、模拟或科学计算中,需要确保每次运行程序时,随机数的生成顺序是相同的,以便复现结果。
  • 调试:当程序中的随机行为导致 bug 时,使用固定种子可以稳定地重现这个 bug。

java.security.SecureRandom

当随机数用于安全目的时(如生成会话ID、临时密码、加密密钥、盐值等),绝对不能使用 Math.random()java.util.Random,必须使用 SecureRandom

特点:

  • 安全性SecureRandom 使用了密码学安全的伪随机数生成器(CSPRNG),它的输出是不可预测的,即使攻击者知道了之前生成的随机数序列,也无法预测下一个数。
  • 性能:比 Random 慢,因为它的算法更复杂,需要从更“熵”(entropy)丰富的来源(如硬件噪声)中获取种子。
  • 使用:与 Random 类似,也需要创建对象。

示例代码:

import java.security.SecureRandom;
public class SecureRandomExample {
    public static void main(String[] args) {
        // 创建一个 SecureRandom 对象
        // 通常不需要指定种子,它会自动从安全的源获取种子
        SecureRandom secureRand = new SecureRandom();
        // 1. 生成一个安全的随机 int
        int secureInt = secureRand.nextInt();
        System.out.println("安全的随机 int: " + secureInt);
        // 2. 生成一个 6 位数的数字验证码
        int verificationCode = 100000 + secureRand.nextInt(900000); // 生成 [100000, 999999]
        System.out.println("6位验证码: " + verificationCode);
        // 3. 生成一个随机的 byte 数组,常用于生成密钥或盐值
        byte[] salt = new byte[16];
        secureRand.nextBytes(salt);
        System.out.print("随机盐值: ");
        for (byte b : salt) {
            System.out.printf("%02x ", b);
        }
    }
}

总结与对比

特性 Math.random() java.util.Random java.security.SecureRandom
类路径 java.lang java.util java.security
类型 double int, long, double, float, boolean Random
范围 [0.0, 1.0) nextInt(int bound)[0, bound) Random
种子 可自定义 自动从安全源获取,也可自定义
性能 较快
安全性 不安全 不安全 安全
主要用途 简单、非关键任务的随机数 普通应用、游戏、模拟等 密码学、安全认证、敏感数据

如何选择?

  • 只是随便搞个随机数,比如游戏里的随机位置、抽奖概率(非关键):用 Math.random()Random 都行。Random.nextInt(bound) 在生成整数时更直观。
  • 需要固定随机数序列来测试或调试:用 new Random(seed)
  • 任何与安全相关的场景必须使用 SecureRandom
    • 生成用户密码、临时令牌。
    • 创建加密密钥或初始化向量。
    • 生成会话 ID。
    • 任何防止被猜测或攻击的场景。

希望这个详细的解释能帮助你完全理解 Java 中的随机数生成!

分享:
扫描分享到社交APP
上一篇
下一篇