ZetCode

Java Random 类

上次修改时间:2025 年 4 月 20 日

Random 类是 Java 实用程序包的一部分,用于生成伪随机数。它提供了一些方法,可以轻松生成随机整数、双精度浮点数、布尔值和高斯分布的值。

=>

随机数生成对于游戏、模拟、密码学和测试至关重要。 Random 类使用 48 位种子和一个线性同余公式来创建伪随机序列。

Random 类概述

Random 类使用由种子值启动的算法生成伪随机数。相同的种子会产生相同的数字序列,有助于保持测试和调试的一致性。

它包括诸如 nextIntnextDoublenextBoolean 之类的方法,用于生成各种随机值。 这些方法是线程安全的,但大量争用可能会影响性能。

基本随机数生成

此示例说明了 Random 类的基本用法,用于在一个简单的程序中创建随机整数、双精度浮点数和布尔值。

BasicRandom.java
package com.zetcode;

import java.util.Random;

public class BasicRandom {

    public static void main(String[] args) {
        
        Random random = new Random();
        
        // Generate random integer
        int randInt = random.nextInt();
        System.out.println("Random integer: " + randInt);
        
        // Generate random integer between 0 (inclusive) and 100 (exclusive)
        int randIntRange = random.nextInt(100);
        System.out.println("Random integer (0-99): " + randIntRange);
        
        // Generate random double between 0.0 and 1.0
        double randDouble = random.nextDouble();
        System.out.println("Random double: " + randDouble);
        
        // Generate random boolean
        boolean randBool = random.nextBoolean();
        System.out.println("Random boolean: " + randBool);
    }
}

该程序实例化一个 Random 对象以生成四个随机值。 不带参数的 nextInt 方法会生成任何整数,而带有边界时,它会生成从 0 到该边界(不包括)的值。

每次执行都会产生唯一的结果,因为 Random 实例使用当前时间作为其默认种子。 这些值在其各自的范围内均匀分布。

种子随机数生成

此示例显示了如何将固定种子与 Random 类一起使用。特定的种子确保了数字序列的一致性,非常适合用于测试和调试目的。

SeededRandom.java
package com.zetcode;

import java.util.Random;

public class SeededRandom {

    public static void main(String[] args) {
        
        // Create two Random instances with the same seed
        Random random1 = new Random(42);
        Random random2 = new Random(42);
        
        System.out.println("First sequence from random1:");
        for (int i = 0; i < 5; i++) {
            System.out.println(random1.nextInt(100));
        }
        
        System.out.println("\nSecond sequence from random2:");
        for (int i = 0; i < 5; i++) {
            System.out.println(random2.nextInt(100));
        }
    }
}

在此,两个 Random 实例使用相同的种子 (42) 初始化。 由于共享的种子值,两者都会生成相同的数字序列。

这种可预测性对于需要可重复结果的应用程序(例如模拟或可重现的游戏状态)至关重要。 如果没有固定种子,每次运行都会产生不同的序列。

生成范围内的随机数

此示例演示了如何在自定义范围内生成随机数,允许生成任何最小值和最大值之间的数字,而不仅仅是从零开始。

RandomRange.java
package com.zetcode;

import java.util.Random;

public class RandomRange {

    public static void main(String[] args) {
        
        Random random = new Random();
        int min = 10;
        int max = 20;
        
        // Method 1: Using nextInt(bound) with adjustment
        int rand1 = random.nextInt(max - min + 1) + min;
        System.out.println("Random between " + min + " and " + max + ": " + rand1);
        
        // Method 2: Using doubles for more flexible ranges
        double rand2 = min + (max - min) * random.nextDouble();
        System.out.println("Random double in range: " + rand2);
    }
}

第一种方法使用带有计算边界的 nextInt 来生成包含范围内的整数。公式为 random.nextInt(max - min + 1) + min

第二种方法使用 nextDouble 生成该范围内的随机双精度浮点数,从而为小数值提供更高的精度。 这两种方法都有效地适用于各种用例。

生成随机字符串

此示例说明了如何使用 Random 类创建随机字符串。 我们实现了一种方法,用于从定义的字符集中生成指定长度的字符串。

RandomString.java
package com.zetcode;

import java.util.Random;

public class RandomString {

    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    public static String generateRandomString(Random random, int length) {
        StringBuilder sb = new StringBuilder(length);
        
        for (int i = 0; i < length; i++) {
            int randomIndex = random.nextInt(CHARACTERS.length());
            char randomChar = CHARACTERS.charAt(randomIndex);
            sb.append(randomChar);
        }
        
        return sb.toString();
    }

    public static void main(String[] args) {
        Random random = new Random();
        
        System.out.println("Random string (8 chars): " + generateRandomString(random, 8));
        System.out.println("Random string (12 chars): " + generateRandomString(random, 12));
        System.out.println("Random string (16 chars): " + generateRandomString(random, 16));
    }
}

我们为随机字符串定义了一个有效字符的常量字符串。 generateRandomString 方法通过从此集合中随机选择字符来构建字符串。

此方法对于创建密码、唯一 ID 或测试数据非常有用。 可以定制字符集,使其仅包含特定应用程序所需的字符。

安全随机数

对于安全关键型任务,Java 提供了 SecureRandom,这是一种密码学上强大的随机数生成器。 此示例显示了其与标准 Random 类相比的用法。

SecureRandomExample.java
package com.zetcode;

import java.security.SecureRandom;
import java.util.Random;

public class SecureRandomExample {

    public static void main(String[] args) {
        
        // Regular Random
        Random random = new Random();
        System.out.println("Regular Random int: " + random.nextInt());
        
        // SecureRandom
        SecureRandom secureRandom = new SecureRandom();
        System.out.println("SecureRandom int: " + secureRandom.nextInt());
        
        // Generating a secure random byte array
        byte[] randomBytes = new byte[16];
        secureRandom.nextBytes(randomBytes);
        System.out.print("SecureRandom bytes: ");
        for (byte b : randomBytes) {
            System.out.printf("%02x", b);
        }
        System.out.println();
    }
}

SecureRandom 提供密码学上强大的随机数,用于生成会话密钥或令牌等任务。 虽然比 Random 慢,但它可以确保更高的随机性。

此示例演示了如何生成整数和字节数组。 字节数组以十六进制显示,以提高清晰度。 对所有加密操作使用 SecureRandom

Random 与流

Java 8 的流与 Random 类无缝集成。 此示例显示了如何生成具有不同特征的随机数流。

RandomStreams.java
package com.zetcode;

import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.DoubleStream;

public class RandomStreams {

    public static void main(String[] args) {
        
        Random random = new Random();
        
        // Generate stream of random integers
        System.out.println("Random integers (limit 5):");
        IntStream intStream = random.ints(5);
        intStream.forEach(System.out::println);
        
        // Generate stream of random integers in range
        System.out.println("\nRandom integers between 50-100 (limit 5):");
        IntStream rangeStream = random.ints(5, 50, 100);
        rangeStream.forEach(System.out::println);
        
        // Generate stream of random doubles
        System.out.println("\nRandom doubles (limit 5):");
        DoubleStream doubleStream = random.doubles(5);
        doubleStream.forEach(System.out::println);
        
        // Generate infinite stream and limit it
        System.out.println("\nRandom Gaussian values (limit 5):");
        random.doubles()
              .map(d -> random.nextGaussian())
              .limit(5)
              .forEach(System.out::println);
    }
}

此示例介绍了四种创建随机数流的方法。 intsdoubleslongs 方法生成原始值的流。

我们展示了具有设定大小的有界流和明确限制的无界流。 最后一个案例生成高斯分布的值,展示了流的随机数功能方法。

性能注意事项

此示例比较了 RandomThreadLocalRandom 在多线程设置中的性能,其中 ThreadLocalRandom 在效率方面表现出色。

RandomPerformance.java
package com.zetcode;

import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class RandomPerformance {

    static final int COUNT = 10000000;

    public static void main(String[] args) {
        
        // Test Random
        long start = System.currentTimeMillis();
        Random random = new Random();
        for (int i = 0; i < COUNT; i++) {
            random.nextInt();
        }
        long duration = System.currentTimeMillis() - start;
        System.out.println("Random time: " + duration + "ms");
        
        // Test ThreadLocalRandom
        start = System.currentTimeMillis();
        for (int i = 0; i < COUNT; i++) {
            ThreadLocalRandom.current().nextInt();
        }
        duration = System.currentTimeMillis() - start;
        System.out.println("ThreadLocalRandom time: " + duration + "ms");
    }
}

ThreadLocalRandom 通过维护每个线程的单独生成器来优化多线程环境中的随机数生成,从而避免了争用。

输出突出显示了性能差异。 对于并发应用程序,ThreadLocalRandom 更可取,但在单线程情况下,差异很小。

生成随机数组

此示例演示了如何使用 Random 类创建填充了随机数的数组,这对于模拟或测试方案很有用。

RandomArray.java
package com.zetcode;

import java.util.Arrays;
import java.util.Random;

public class RandomArray {

    public static void main(String[] args) {
        
        Random random = new Random();
        int size = 10;
        
        // Generate array of random integers
        int[] intArray = new int[size];
        for (int i = 0; i < size; i++) {
            intArray[i] = random.nextInt(100);
        }
        System.out.println("Random integer array: " + Arrays.toString(intArray));
        
        // Generate array of random doubles
        double[] doubleArray = new double[size];
        for (int i = 0; i < size; i++) {
            doubleArray[i] = random.nextDouble();
        }
        System.out.println("Random double array: " + Arrays.toString(doubleArray));
    }
}

该程序创建两个数组:一个包含随机整数,另一个包含随机双精度浮点数。 每个元素都是使用 Random 类生成的。

这样的数组对于测试算法或模拟数据集很有用。 Arrays.toString 方法格式化输出,以便于阅读。

从列表中随机选择

此示例显示了如何使用 Random 类从列表中随机选择元素,这在游戏或采样应用程序中是一项常见任务。

RandomSelection.java
package com.zetcode;

import java.util.List;
import java.util.Random;

public class RandomSelection {

    public static void main(String[] args) {

        Random random = new Random();
        List<String> items = List.of("Apple", "Banana", 
            "Orange", "Grape", "Mango");

        // Select one random item
        int index = random.nextInt(items.size());
        String randomItem = items.get(index);
        System.out.println("Random item: " + randomItem);

        // Select multiple random items (with replacement)
        System.out.println("Three random items:");
        for (int i = 0; i < 3; i++) {
            index = random.nextInt(items.size());
            System.out.println(items.get(index));
        }
    }
}

我们使用 nextInt 在列表的范围内生成一个随机索引,然后检索该索引处的元素以进行单个或多个选择。

此技术适用于游戏中的随机项目选择或采样数据等场景。 该示例包括替换选择,允许重复项目。

生成随机高斯值

此示例探讨了 Random 类生成高斯(正态分布)随机数的能力,这在统计模拟中很有用。

RandomGaussian.java
package com.zetcode;

import java.util.Random;

public class RandomGaussian {

    public static void main(String[] args) {
        
        Random random = new Random();
        
        // Generate 5 Gaussian random numbers
        System.out.println("Gaussian random values (mean 0, std dev 1):");
        for (int i = 0; i < 5; i++) {
            double gaussian = random.nextGaussian();
            System.out.printf("%.4f%n", gaussian);
        }
        
        // Scale Gaussian values to custom mean and standard deviation
        double mean = 100;
        double stdDev = 15;
        System.out.println("\nScaled Gaussian values (mean 100, std dev 15):");
        for (int i = 0; i < 5; i++) {
            double scaled = mean + random.nextGaussian() * stdDev;
            System.out.printf("%.4f%n", scaled);
        }
    }
}

nextGaussian 方法生成平均值为 0,标准偏差为 1 的数字。我们还展示了缩放到自定义平均值和偏差。

这非常适合用于建模自然现象或统计数据。 缩放值演示了如何使高斯数适应特定要求。

来源

Java Random 文档

本教程全面探讨了 Java Random 类,涵盖了基本用法、种子生成、范围创建、安全选项和性能。 随机数生成对于许多应用程序至关重要。

作者

我是 Jan Bodnar,一位充满激情的程序员,拥有丰富的经验。 自 2007 年以来,我撰写了 1,400 多篇文章和 8 本电子书。 拥有超过 8 年的教学经验,我致力于分享知识并帮助他人学习编程概念。

列出所有Java教程