Java中的随机数

本文详细介绍了Java中Random类的使用方法,包括无种子和有种子实例,常用方法如nextInt、nextBoolean、nextDouble的用法,并展示了如何生成不同区间和精度的随机数,以及如何利用Math.abs()进行限制。实例涵盖了随机整数、小数和布尔值的生成,以及如何在实际项目中运用这些技巧。

在Java中,随机数的概念从广义上将,有三种。
  1、通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字。
  2、通过Math.random()返回一个0到1之间的double值。
  3、通过Random类来产生一个随机数,这个是专业的Random工具类,功能强大。

(int)(1+Math.random()*(10-1+1)) ----- 从1到10的int型随数

Random

需要说明的是,Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率是均等的。
Random r = new Random(); 没有给种子,用的是默认种子,是当前时间的毫秒值
Random r1 = new Random(10); 给出指定的种子
再次强调:种子数只是随机算法的起源数字,和生成的随机数字的区间无关。
在这里插入图片描述
无参:
同样的程序运行两次得到的结果并不相同,是因为在创建Random对象时没有传入种子参数,程序会自动以当前时间为时间戳。所以每一次的运行结果都是不同的。

import java.util.Random;
public class RandomTest{
	public static void main(String[] args)throws Exception{
        Random r=new Random();   //不传入种子
        for(int i=0;i<8;i++){
        	System.out.println(r.nextInt(100));
        }
	}
}

有参:
无论运行多少次,结果完全相同,那是因为创建Random对象时传入了参数,两次运行时种子相同。

import java.util.Random;
public class RandomTest{
	public static void main(String[] args)throws Exception{
        Random r=new Random(100);   //传入种子
        for(int i=0;i<8;i++){
        	System.out.println(r.nextInt(100));
        }
	}
}

Random中的方法

其中常用的:
Random类的nextDouble()方法返回的是0.0至1.0之间的double类型值。
nextFloat()方法返回的是0.0至1.0之间的float类型值。
nextInt(int n)返回的是0(包括)至n(不包括)之间的int值。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

a、public boolean nextBoolean()

该方法的作用是生成一个随机的boolean值,生成true和false的值几率相等,也就是都是50%的几率。

b、public double nextDouble()

该方法的作用是生成一个随机的double值,数值介于[0,1.0)之间。

c、public int nextInt()

该方法的作用是生成一个随机的int值,该值介于int的区间,也就是-231 到 231-1之间。

如果需要生成指定区间的int值,则需要进行一定的数学变换,具体可以参看下面的使用示例中的代码。

d、public int nextInt(int n)

该方法的作用是生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n。

如果想生成指定区间的int值,也需要进行一定的数学变换,具体可以参看下面的使用示例中的代码。

e、public void setSeed(long seed)

该方法的作用是重新设置Random对象中的种子数。设置完种子数以后的Random对象和相同种子数使用new关键字创建出的Random对象相同。

技巧

使用 Math.abs() 限制随机数为非负数
选择哪种小数:
其中的nextFloat(),nextDouble()方法分别生成0-1的8位有限小数,16位有限小数的随机数。

案例应用

生成[0,d)区间的随机小数: random.nextDouble() * d;
生成[1,d)区间的随机小数: random.nextDouble() * d+1;
生成[5.0,8.0]区间的随机小数: random.nextDouble()*(8.0-5.0+0.1)+5.0;

Random r = new Random();

a、生成[0,1.0)区间的小数,直接使用nextDouble方法获得。
double d1 = r.nextDouble();

b、生成[0,5.0)区间的小数

double d2 = r.nextDouble() * 5;
因为nextDouble方法生成的数字区间是[0,1.0),将该区间扩大5倍即是要求的区间。
同理,生成[0,d)区间的随机小数,d为任意正的小数,则只需要将nextDouble方法的返回值乘以d即可。

c、生成[1,2.5)区间的小数

double d3 = r.nextDouble() * 1.5 + 1;
生成[1,2.5)区间的随机小数,则只需要首先生成[0,1.5)区间的随机数字,然后将生成的随机数区间加1即可。

同理,生成任意非从0开始的小数区间[d1,d2)范围的随机数字(其中d1不等于0),则只需要首先生成[0,d2-d1)区间的随机数字,然后将生成的随机数字区间加上d1即可。

//nextDouble 范围:[0.0-1.0)  目标:[5.0-8.0)
double v = random.nextDouble() * 3 + 5;  //[0.0-3.0) + 5 = [5.0-8.0)
//  [0.0-1.0) +[0,2] + 5 = [5.0-8.0)
double v2 = random.nextDouble() + random.nextInt(3) + 5;//

在这里插入图片描述

d、生成任意整数

int n1 = r.nextInt();  直接使用nextInt方法即可。

e、生成[0,10)区间的整数  以下两行代码均可生成[0,10)区间的整数。

int n2 = r.nextInt(10);  使用Random类中的nextInt(int n)方法直接实现。

n2 = Math.abs(r.nextInt() % 10);
第二种实现中,首先调用nextInt()方法生成一个任意的int数字,该数字和10取余以后生成的数字区间为(-10,10),然后再对该区间求绝对值,则得到的区间就是[0,10)了。

同理,生成任意[0,n)区间的随机整数,都可以使用如下代码:

int n2 = r.nextInt(n);
n2 = Math.abs(r.nextInt() % n);

f、生成[0,10]区间的整数等价于[0,11)

int n3 = r.nextInt(11);
n3 = Math.abs(r.nextInt() % 11);
相对于整数区间,[0,10]区间和[0,11)区间等价,所以即生成[0,11)区间的整数。

g、生成[-3,15)区间的整数

int n4 = r.nextInt(18) - 3;
n4 = Math.abs(r.nextInt() % 18) - 3;
生成非从0开始区间的随机整数,可以参看上面非从0开始的小数区间实现原理的说明。

Math.random()方法生成0.01.0(不包含1.0)double型随机数,一般地, a + Math.random() * b可以返回a到a+b之间的随机数,不包括a+b.

生成伪随机数并保存到数组中

 public static void main(String[] args) {
        Random random = new Random();
        //生成伪随机数并保存到数组中
        byte[] bs = new byte[5];
        random.nextBytes(bs);
        for (byte b : bs) {
            System.out.print(b + ", ");
        }

    }
nextLong()%n使其随机数区间在(-n,n)
输出(-10,10)的随机数
Long temp = rd.nextLong()%10;

其中的nextFloat(),nextDouble()方法分别生成0-18位有限小数,16位有限小数的随机数。
输出16位有限小数的随机数。
double temp = Math.abs( rd.nextDouble())%10;

在这里插入图片描述

在这里插入图片描述

其他随机数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

众所周知,随机数是任何一种编程语言最基本的特征之一。而生成随机数的基本方式也是相同的:产生一个0到1之间的随机数。看似简单,但有时我们也会忽略了一些有趣的功能。 我们从书本上学到什么? 最明显的,也是直观的方式,在Java中生成随机数只要简单的调用: 1.java.lang.Math.random() 在所有其他语言中,生成随机数就像是使用Math工具类,如abs, pow, floor, sqrt和其他数学函数。大多数人通过书籍、教程和课程来了解这个类。一个简单的例子:从0.0到1.0之间可以生成一个双精度浮点数。那么通过上面的信息,开发人员要产生0.0和10.0之间的双精度浮点数会这样来写: 1.Math.random() * 10 而产生0和10之间的整数,则会写成: 1.Math.round(Math.random() * 10) 进阶 通过阅读Math.random()的源码,或者干脆利用IDE的自动完成功能,开发人员可以很容易发现,java.lang.Math.random()使用一个内部的随机生成对象 - 一个很强大的对象可以灵活的随机产生:布尔值、所有数字类型,甚至是高斯分布。例如: 1.new java.util.Random().nextInt(10) 它有一个缺点,就是它是一个对象。它的方法必须是通过一个实例来调用,这意味着必须先调用它的构造函数。如果在内存充足的情况下,像上面的表达式是可以接受的;但内存不足时,就会带来问题。 一个简单的解决方案,可以避免每次需要生成一个随机数时创建一个新实例,那就是使用一个静态类。猜你可能想到了java.lang.Math,很好,我们就是改良java.lang.Math的初始化。虽然这个工程量低,但你也要做一些简单的单元测试来确保其不会出错。 假设程序需要生成一个随机数来存储,问题就又来了。比如有时需要操作或保护种子(seed),一个内部数用来存储状态和计算下一个随机数。在这些特殊情况下,共用随机生成对象是不合适的。 并发 在Java EE多线程应用程序的环境中,随机生成实例对象仍然可以被存储在类或其他实现类,作为一个静态属性。幸运的是,java.util.Random是线程安全的,所以不存在多个线程调用会破坏种子(seed)的风险。 另一个值得考虑的是多线程java.lang.ThreadLocal的实例。偷懒的做法是通过Java本身API实现单一实例,当然你也可以确保每一个线程都有自己的一个实例对象。 虽然Java没有提供一个很好的方法来管理java.util.Random的单一实例。但是,期待已久的Java 7提供了一种新的方式来产生随机数: 1.java.util.concurrent.ThreadLocalRandom.current().nextInt(10) 这个新的API综合了其他两种方法的优点:单一实例/静态访问,就像Math.random()一样灵活。ThreadLocalRandom也比其他任何处理高并发的方法要更快。 经验 Chris Marasti-Georg 指出: 1.Math.round(Math.random() * 10) 使分布不平衡,例如:0.0 - 0.499999将四舍五入为0,而0.5至1.499999将四舍五入为1。那么如何使用旧式语法来实现正确的均衡分布,如下: 1.Math.floor(Math.random() * 11) 幸运的是,如果我们使用java.util.Random或java.util.concurrent.ThreadLocalRandom就不用担心上述问题了。 Java实战项目里面介绍了一些不正确使用java.util.Random API的危害。这个教训告诉我们不要使用: 1.Math.abs(rnd.nextInt())%n 而使用: 1.rnd.nextInt(n)
<think>好的,我现在需要回答用户关于如何在Java中生成随机数的问题。根据用户提供的引用内容,我需要整理出不同的方法并解释它们的实现方式。首先,用户提到了java.util.Random类和Math.random()方法,这两个是基本的方法。然后还有Java 7引入的ThreadLocalRandom,以及可能的区间随机数的生成。 首先,我应该按照时间顺序或者常用程度来组织这些方法。可能从最基础的开始,比如Math.random(),因为它简单,但功能有限。接着介绍Random类,详细说明如何创建实例和使用nextInt等方法。然后,提到Random类的线程安全问题,进而引出Java 7的ThreadLocalRandom,解释它的优势和使用方式。 接下来需要考虑生成指定区间的随机数,比如如何生成0到某个数之间的随机数,或者一个闭区间的随机数,比如[min, max]。这里可能需要数学公式,比如nextInt(max - min + 1) + min。需要确保这里的公式用LaTeX格式,比如$[0, n)$和$[min, max]$。 另外,用户提供的引用中提到不带参数的Random构造函数产生的随机数不会重复,但某些情况下可能重复。需要澄清这一点,实际上随机数生成器是伪随机的,种子相同的话序列会重复,所以如果使用相同种子可能会得到重复的序列,但一般情况下不带参数的构造函数使用系统时间作为种子,所以不同的实例会产生不同的序列。 在代码示例方面,需要给出不同方法的代码片段,比如使用Math.random()生成0-100的整数,使用Random类生成区间数,以及ThreadLocalRandom的例子。要确保代码语法正确,比如在Java中正确调用方法。 可能还需要提到线程安全的问题,比如在多线程环境下使用Random可能导致性能问题,因此推荐使用ThreadLocalRandom来提高并发性能。同时,注意每个方法的优缺点,比如Math.random()返回的是double类型,需要转换才能得到整数,而Random类更灵活。 最后,生成相关问题,可能涉及性能比较、种子设置的影响、随机数的应用场景等。需要确保问题相关且有价值,帮助用户进一步学习。 现在,需要检查是否符合用户的要求:结构清晰,分步骤解释,使用正确的LaTeX格式,引用标记正确,代码块正确,以及生成相关问题。同时要使用中文回答,避免使用Markdown格式,除了代码块需要用三个反引号包裹。</think>### Java生成随机数的方法及实现方式 #### 1. **Math.random() 方法** - **功能**:生成$[0, 1)$范围内的`double`类型伪随机数。 - **实现**: ```java double random = Math.random(); // 生成0.0 ≤ random < 1.0 int num = (int)(Math.random() * 100); // 生成0-99的整数 ``` - **特点**:简单易用,但功能有限,适用于简单场景[^1]。 #### 2. **java.util.Random 类** - **功能**:支持多种数据类型(整数、浮点数、布尔值等)的随机数生成。 - **实现**: ```java Random rd = new Random(); int num1 = rd.nextInt(); // 任意整数 int num2 = rd.nextInt(100); // 生成0-99的整数 double num3 = rd.nextDouble(); // 生成0.0 ≤ num3 < 1.0 ``` - **区间随机数**:生成$[min, max]$范围的整数: ```java int min = 10, max = 20; int num = rd.nextInt(max - min + 1) + min; // 10 ≤ num ≤ 20 ``` - **注意**:默认构造函数以系统时间为种子,不同实例生成不同序列[^3]。 #### 3. **ThreadLocalRandom(Java 7+)** - **功能**:针对多线程优化的高性能随机数生成器。 - **实现**: ```java int num = ThreadLocalRandom.current().nextInt(1, 100); // 生成1-99的整数 ``` - **特点**:避免多线程竞争,性能优于`Random`[^2]。 #### 4. **SecureRandom 类** - **功能**:生成高安全性的随机数(如加密场景)。 - **实现**: ```java SecureRandom sr = new SecureRandom(); int secureNum = sr.nextInt(); ``` ### 代码示例对比 | 方法 | 代码示例 | 适用场景 | |--------------------|-------------------------------------------|------------------| | `Math.random()` | `(int)(Math.random() * 100)` | 简单单线程需求 | | `Random` | `new Random().nextInt(100)` | 通用随机需求 | | `ThreadLocalRandom`| `ThreadLocalRandom.current().nextInt(1,5)`| 高并发多线程场景 |
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值