本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示。

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

第1种


通过System.currentTimeMillis()来获取随机数。实际上是获取当前时间毫秒数,它是long类型。使用方法如下:

final long l = System.currentTimeMillis();

若要获取int类型的整数,只需要将上面的结果转行成int类型即可。比如,获取[0, 100)之间的int整数。方法如下:

final long l = System.currentTimeMillis();
final int i = (int)( l % 100 );

第2种


通过Math.random()来获取随机数。实际上,它返回的是0(包含)到1(不包含)之间的double值。使用方法如下:

final double d = Math.random();

若要获取int类型的整数,只需要将上面的结果转行成int类型即可。比如,获取[0, 100)之间的int整数。方法如下:

final double d = Math.random();
final int i = (int)(d*100);

Math.random();方法执行的本质是调用Random.nextDouble()方法;这里来看一个Math.random()的源码:

private static Random randomNumberGenerator;  //定义一个Random的私有的静态的变量
// 对Random进行初始化操作
private static synchronized Random initRNG() {
Random rnd = randomNumberGenerator;
return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd;
}
public static double random() {
Random rnd = randomNumberGenerator;
if (rnd == null) rnd = initRNG();
return rnd.nextDouble();
}
对上述源码进行简单解析:首先定义一个private static 的Random变量,这样所有的Math对象都可以共享这个类变量,而且只用初始化一次就可以,
    执行random()方法的时候,首先判断类random变量是否已经被赋值,如果为null,则进行初始化操作,(初始化过程用Synchronized进行同步,适用于多线程环境);
    如果对象不为null,说明已经完成了初始化操作,那么直接调用random的nextDouble()方法。
如果只涉及到单线程的话,这个操作等价于Random random = new Random(); return random.nextDouble();

第3种


通过Random类来获取随机数。

使用方法如下:
(01) 创建Random对象。有两种方法可以创建Random对象,如下:

Random random = new Random();//默认构造方法
Random random = new Random(1000);//指定种子数字

(02) 通过Random对象获取随机数。Random支持的随机值类型包括:boolean, byte, int, long, float, double。
比如,获取[0, 100)之间的int整数。方法如下:

int i2 = random.nextInt(100);

Random 的函数接口


// 构造函数(一): 创建一个新的随机数生成器。
Random()
// 构造函数(二): 使用单个 long 种子创建一个新随机数生成器: public Random(long seed) { setSeed(seed); } next 方法使用它来保存随机数生成器的状态。
Random(long seed) boolean nextBoolean() // 返回下一个“boolean类型”伪随机数。
void nextBytes(byte[] buf) // 生成随机字节并将其置于字节数组buf中。
double nextDouble() // 返回一个“[0.0, 1.0) 之间的double类型”的随机数。
float nextFloat() // 返回一个“[0.0, 1.0) 之间的float类型”的随机数。
int nextInt() // 返回下一个“int类型”随机数。
int nextInt(int n) // 返回一个“[0, n) 之间的int类型”的随机数。
long nextLong() // 返回下一个“long类型”随机数。
synchronized double nextGaussian() // 返回下一个“double类型”的随机数,它是呈高斯(“正常地”)分布的 double 值,其平均值是 0.0,标准偏差是 1.0。
synchronized void setSeed(long seed) // 使用单个 long 种子设置此随机数生成器的种子。

接口源码实现:

//最基本的方法,所有的随机数生成方法都调用了他,同时可以看到,Random采用的种子是AtomicLong类型的原子类,next方法来进行求解的时候使用了CAS机制保证了操作的原子类与线程安全性

protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
} //nextInt()调用了next(32)方法
public int nextInt() {
return next(32);
}

//nextInt(n)调用了next(31)方法,然后对n取余,这样就可以求得[0,n)之内的随机数了
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive"); if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31); int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
//调用了next(32),然后左移32位,在加上next(32)
public long nextLong() {
// it's okay that the bottom word remains signed.
return ((long)(next(32)) << 32) + next(32);
}
//调用了next(1),判断结果是否是0来生成true还是false
public boolean nextBoolean() {
return next(1) != 0;
}

//调用了next(24)
public float nextFloat() {
return next(24) / ((float)(1 << 24));
}
//调用了next(26)与next(27)
public double nextDouble() {
return (((long)(next(26)) << 27) + next(27))
/ (double)(1L << 53);
}
note:Random是线程安全的,用AtomicLong原子类以及CAS机制保证了操作的原子性,在进行种子设置的时候采用synchronized保证了操作的同步性,
    但是多线程环境中,不建议采用Random方法,影响性能,建议采用java.util.concurrent.ThreadLocalRandom类,如果强调加密的安全性,
    建议使用java.security.SecureRandom.
 

获取随机数示例


下面通过示例演示上面3种获取随机数的使用方法。
源码如下(RandomTest.java):

 1 import java.util.Random;
2 import java.lang.Math;
3
4 /**
5 * java 的随机数测试程序。共3种获取随机数的方法:
6 * (01)、通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字。
7 * (02)、通过Math.random()返回一个0到1之间的double值。
8 * (03)、通过Random类来产生一个随机数,这个是专业的Random工具类,功能强大。
9 *
10 * @author skywang
11 * @email kuiwu-wang@163.com
12 */
13 public class RandomTest{
14
15 public static void main(String args[]){
16
17 // 通过System的currentTimeMillis()返回随机数
18 testSystemTimeMillis();
19
20 // 通过Math的random()返回随机数
21 testMathRandom();
22
23 // 新建“种子为1000”的Random对象,并通过该种子去测试Random的API
24 testRandomAPIs(new Random(1000), " 1st Random(1000)");
25 testRandomAPIs(new Random(1000), " 2nd Random(1000)");
26 // 新建“默认种子”的Random对象,并通过该种子去测试Random的API
27 testRandomAPIs(new Random(), " 1st Random()");
28 testRandomAPIs(new Random(), " 2nd Random()");
29 }
30
31 /**
32 * 返回随机数-01:测试System的currentTimeMillis()
33 */
34 private static void testSystemTimeMillis() {
35 // 通过
36 final long l = System.currentTimeMillis();
37 // 通过l获取一个[0, 100)之间的整数
38 final int i = (int)( l % 100 );
39
40 System.out.printf("\n---- System.currentTimeMillis() ----\n l=%s i=%s\n", l, i);
41 }
42
43
44 /**
45 * 返回随机数-02:测试Math的random()
46 */
47 private static void testMathRandom() {
48 // 通过Math的random()函数返回一个double类型随机数,范围[0.0, 1.0)
49 final double d = Math.random();
50 // 通过d获取一个[0, 100)之间的整数
51 final int i = (int)(d*100);
52
53 System.out.printf("\n---- Math.random() ----\n d=%s i=%s\n", d, i);
54 }
55
56
57 /**
58 * 返回随机数-03:测试Random的API
59 */
60 private static void testRandomAPIs(Random random, String title) {
61 final int BUFFER_LEN = 5;
62
63 // 获取随机的boolean值
64 boolean b = random.nextBoolean();
65 // 获取随机的数组buf[]
66 byte[] buf = new byte[BUFFER_LEN];
67 random.nextBytes(buf);
68 // 获取随机的Double值,范围[0.0, 1.0)
69 double d = random.nextDouble();
70 // 获取随机的float值,范围[0.0, 1.0)
71 float f = random.nextFloat();
72 // 获取随机的int值
73 int i1 = random.nextInt();
74 // 获取随机的[0,100)之间的int值
75 int i2 = random.nextInt(100);
76 // 获取随机的高斯分布的double值
77 double g = random.nextGaussian();
78 // 获取随机的long值
79 long l = random.nextLong();
80
81 System.out.printf("\n---- %s ----\nb=%s, d=%s, f=%s, i1=%s, i2=%s, g=%s, l=%s, buf=[",
82 title, b, d, f, i1, i2, g, l);
83 for (byte bt:buf)
84 System.out.printf("%s, ", bt);
85 System.out.println("]");
86 }
87 }

Java随机数的更多相关文章

  1. Java 随机数

    本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示. 广义上讲,Java中的随机数的有三种产生方式:(01). 通过System.currentTimeMillis()来获取一个当前时间 ...

  2. 学习记录 java随机数的产生机制

    java 随机数 一.在j2se里我们可以使用Math.random()方法来产生一个随机数,这个产生的随机数是0-1之间的一个double,我们可以把他乘以一定的数,比如说乘以100,他就是个100 ...

  3. java随机数与数组的使用。

    java随机数与数组的使用.    一:题目 二 代码:  public class Students {    int number;  // 学号    int State ;   // 年级   ...

  4. Java随机数和UUID

    Java随机数和UUID Java随机数 在Java项目中通常是通过Math.random方法和Random类来获得随机数,前者通过生成一个Random类的实例来实现. 此类产生的是一组伪随机数流,通 ...

  5. java 随机数高效生成

    分享牛,分享牛原创.近期去面试经常被问到java如何生产随机数,以及生成很大的字符串保证不能重复,还要考虑性能,之前本人面试别人的时候,可能不会问这个问题.既然这个java随机数问题经常被问到,那咱们 ...

  6. (转)Java随机数

    1 随机数的三种产生方式 本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示. 广义上讲,Java中的随机数的有三种产生方式: (01). 通过System.currentTimeMil ...

  7. java 随机数 <%=System.currentTimeMillis() %>

    java 随机数<c:set var="version" value="<%=System.currentTimeMillis() %>"/& ...

  8. 硬核 - Java 随机数相关 API 的演进与思考(上)

    本系列将 Java 17 之前的随机数 API 以及 Java 17 之后的统一 API 都做了比较详细的说明,并且将随机数的特性以及实现思路也做了一些简单的分析,帮助大家明白为何会有这么多的随机数算 ...

  9. 硬核 - Java 随机数相关 API 的演进与思考(下)

    本系列将 Java 17 之前的随机数 API 以及 Java 17 之后的统一 API 都做了比较详细的说明,并且将随机数的特性以及实现思路也做了一些简单的分析,帮助大家明白为何会有这么多的随机数算 ...

随机推荐

  1. Windows Server 2008 R2 安装及配置指南

    一.安装需求: 1. 硬件需求条件 硬件 需求 处理器 最低:1.4 GHz(x64处理器) 注意:Windows Server 2008 for Itanium-Based Systems 版本需要 ...

  2. Powerdesigner中如何生成测试数据

    设计表完成以后,我们需要生成一些测试数据,可以直接更新到数据库中,下面我们就来试试: 第一步:建立需要的Profiles测试文件,[Model]--[Test Data Profiles],如图所示: ...

  3. php读取操作大文件

    在php中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file.file_get_contents之类的函数,简简单单的几行代码就能 很漂亮的完成我们所需要的功能.但当所操作的文件是一个比较大的 ...

  4. JS1 js获取dom元素方法

     js获取dom元素方法  1.通过ID选取元素(getElementById) 1)使用方法:document.getElementById("domId")         其 ...

  5. [访问系统] Api_Win32_Mac类工具包 (转载)

    点击下载 Api_Win32_Mac.zip using System; using System.Collections.Generic; using System.Linq; using Syst ...

  6. JavaScript获取网页属性包括宽、高等

    function getWindowInfo() {var s = ""; s += " 网页可见区域宽:"+ document.body.clientWidt ...

  7. ios专题 - APP设计流程

    网上看到这篇文章,觉得基本的flow很有帮助,转过来收藏了:作者:关于Sarah Parmenter英国艾塞克斯(英国英格兰东南部的郡)Youknowwho设计工作室的创始人,Sarah Parmen ...

  8. js操作数据库实现注册和登陆

    自从node-js出现之后,不只是java,php等后端语言可以操作数据库,进行内容的增删改查,javascript简本语言同样具备了该项技能,而且在node下,js具备了很强的操作性和代码的阅读性, ...

  9. Fast Report Data Filter

    使用Data Filter两种方式:一种是 直接在Filter 属性里写表达式 ,另外一种就是在beforePrint 事件里写方法. 今天开发时遇到了一个Filter的问题,不知道是不是fast r ...

  10. a-b(高精度)

    我现在已经是才语言中的一员了,我在此献上今日的佳作——a-b(高精度),以下是我的程序及其注释,欢迎各位来观赏,耶! 程序: #include<stdio.h> #include<s ...