Saul's blog Saul's blog
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)

Saul.J.Wu

立身之本,不在高低。
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)
  • Java入门基础

  • Java核心基础

    • 多线程

    • Java常用类

      • 字符串相关的类
      • JDK8之前日期时间API
      • JDK8中新日期时间API
      • Java比较器
      • 其他类
      • Java随机数
        • 前言
        • 方式
        • Math.random()
          • 例1
          • 例2
        • Random类
          • 常用方法
          • 使用示例
        • System.currentTimeMillis()
        • 实例学习
          • 实例1
          • 实例2
          • 实例3
          • 实例4
          • 实例5
    • 枚举类与注解

    • Java集合

    • 数据结构与算法

    • 泛型

    • IO流

    • 网络编程

    • 反射

    • 函数式编程

  • 设计模式

  • Web开发

  • SpringBoot

  • 微服务

  • Elasticsearch

  • 运维

  • 后端
  • Java核心基础
  • Java常用类
SaulJWu
2020-12-06

Java随机数

# 前言

此文章摘自:实例解析常用的java随机数生成办法_w3cschool https://www.w3cschool.cn/java/java-random.html

随机数是任何一种编程语言最基本的特征之一,在技术开发中应用很广泛,因为有时我们需要随机生成一个固定长度的数字、字符串亦或者是需要随机生成一个不定长度的数字、或者进行一个模拟的随机选择等。Java就为我们提供了最基本的工具,可以帮助开发者生成不同条件下需要的随机数。

# 方式

java中产生随机数和c的差不多,一般有两种随机数,一个是Math中random()方法,一个是Random类。不过不管是c还是java,要产生随机数都需要设置随机数种子,如果设置的是一样的话,每次获得的随机数是一样的。下面来汇总一下常见的不同类型的java随机数是如何生成的。

# Math.random()

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

(数据类型)(最小值+Math.random()*(最大值-最小值+1))

# 例1

从1到10的int型随数

(int)(1+Math.random()*(10-1+1))
1

# 例2

随机生成0~100中的其中一个数

在上面我们已经知道了Math.random()返回的只是从0到1之间的小数,如果要50到100,就先放大50倍,即0到50之间,这里还是小数,如果要整数,就强制转换int,然后再加上50即为50~100。

(int)(Math.random()*50) + 50
1

# Random类

在java.util这个包里面提供了一个Random的类,我们可以新建一个Random的对象来产生随机数,他可以产生随机整数、随机float、随机double,随机long,这个也是我们在j2me的程序里经常用的一个取随机数的方法。

默认构造方法:

Random random = new Random();//默认构造方法
1

指定随机种子:

Random random = new Random(1000);//指定种子数字
1

在进行随机时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字。

相同种子数的Random对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的Random对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。

例:获取[0, 100)之间的int整数。

int i2 = random.nextInt(100);
1

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 种子设置此随机数生成器的种子。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 常用方法

Random 类中的方法比较简单,每个方法的功能也很容易理解。需要说明的是,Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率是均等的。下面对这些方法做一下基本的介绍:

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

  • public double nextDouble() 该方法的作用是生成一个随机的double值,数值介于[0,1.0)之间,这里中括号代表包含区间端点,小括号代表不包含区间端点,也就是0到1之间的随机小数,包含0而不包含1.0。

  • public int nextInt() 该方法的作用是生成一个随机的int值,该值介于int的区间,也就是-2的31次方到2的31次方-1之间。 如果需要生成指定区间的int值,则需要进行一定的数学变换,具体可以参看下面的使用示例中的代码。

  • public int nextInt(int n) 该方法的作用是生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n。 如果想生成指定区间的int值,也需要进行一定的数学变换,具体可以参看下面的使用示例中的代码。

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

# 使用示例

使用Random类,一般是生成指定区间的随机数字,下面就一一介绍如何生成对应区间的随机数字。以下生成随机数的代码均使用以下Random对象r进行生成:

Random r = new Random();
1
  • 生成[0,1.0)区间的小数
 double d1 = r.nextDouble();
1

直接使用nextDouble方法获得。

  • 生成[0,5.0)区间的小数
double d2 = r.nextDouble() * 5;
1

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

  • 生成[1,2.5)区间的小数 [n1,n2]
double d3 = r.nextDouble() * 1.5 + 1;//【也就是 r.nextDouble() * (n2-n1)+n1】
1

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

  • 生成任意整数
int n1 = r.nextInt();
1

直接使用nextInt方法即可。

  • 生成[0,10)区间的整数
int n2 = r.nextInt(10);
n2 = Math.abs(r.nextInt() % 10);
1
2

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

第一种实现使用Random类中的nextInt(int n)方法直接实现。 第二种实现中,首先调用nextInt()方法生成一个任意的int数字,该数字和10取余以后生成的数字区间为(-10,10),因为按照数学上的规定余数的绝对值小于除数,然后再对该区间求绝对值,则得到的区间就是[0,10)了。

  • 同理,生成任意[0,n)区间的随机整数,都可以使用如下代码
int n2 = r.nextInt(n);
n2 = Math.abs(r.nextInt() % n);
1
2
  • 生成[0,10]区间的整数
int n3 = r.nextInt(11);
n3 = Math.abs(r.nextInt() % 11);
1
2

相对于整数区间,[0,10]区间和[0,11)区间等价,所以即生成[0,11)区间的整数。

  • 生成[-3,15)区间的整数
int n4 = r.nextInt(18) - 3;   //【也就是 r.nextInt() * (n2-n1)+n1】 n1是个负数
n4 = Math.abs(r.nextInt() % 18) - 3;   
1
2

生成非从0开始区间的随机整数,可以参看上面非从0开始的小数区间实现原理的说明。

# System.currentTimeMillis()

**方法三:通过System.currentTimeMillis()**来获取一个当前时间毫秒数的long型数字。

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

final long l = System.currentTimeMillis();
1

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

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

# 实例学习

# 实例1

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

package randomTest;

import java.util.Random;

public class Demo1 {
    public static void main(String args[]){

        // 通过System的currentTimeMillis()返回随机数
        testSystemTimeMillis();

        // 通过Math的random()返回随机数
        testMathRandom();

        // 新建“种子为1000”的Random对象,并通过该种子去测试Random的API
        testRandomAPIs(new Random(1000), " 1st Random(1000)");
        testRandomAPIs(new Random(1000), " 2nd Random(1000)");
        // 新建“默认种子”的Random对象,并通过该种子去测试Random的API
        testRandomAPIs(new Random(), " 1st Random()");
        testRandomAPIs(new Random(), " 2nd Random()");
    }

    /**
     * 返回随机数-01:测试System的currentTimeMillis()
     */
    private static void testSystemTimeMillis() {
        // 通过
        final long l = System.currentTimeMillis();
        // 通过l获取一个[0, 100)之间的整数
        final int i = (int)( l % 100 );

        System.out.printf("\n---- System.currentTimeMillis() ----\n l=%s i=%s\n", l, i);
    }

    /**
     * 返回随机数-02:测试Math的random()
     */
    private static void testMathRandom() {
        // 通过Math的random()函数返回一个double类型随机数,范围[0.0, 1.0)
        final double d = Math.random();
        // 通过d获取一个[0, 100)之间的整数
        final int i = (int)(d*100);

        System.out.printf("\n---- Math.random() ----\n d=%s i=%s\n", d, i);
    }


    /**
     * 返回随机数-03:测试Random的API
     */
    private static void testRandomAPIs(Random random, String title) {
        final int BUFFER_LEN = 5;

        // 获取随机的boolean值
        boolean b = random.nextBoolean();
        // 获取随机的数组buf[]
        byte[] buf = new byte[BUFFER_LEN];
        random.nextBytes(buf);
        // 获取随机的Double值,范围[0.0, 1.0)
        double d = random.nextDouble();
        // 获取随机的float值,范围[0.0, 1.0)
        float f = random.nextFloat();
        // 获取随机的int值
        int i1 = random.nextInt();
        // 获取随机的[0,100)之间的int值
        int i2 = random.nextInt(100);
        // 获取随机的高斯分布的double值
        double g = random.nextGaussian();
        // 获取随机的long值
        long l = random.nextLong();

        System.out.printf("\n---- %s ----\nb=%s, d=%s, f=%s, i1=%s, i2=%s, g=%s, l=%s, buf=[",
                title, b, d, f, i1, i2, g, l);
        for (byte bt:buf){
            System.out.printf("%s, ", bt);
        }
        System.out.println("]");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

上面代码输出结果:

---- System.currentTimeMillis() ----
 l=1607301480501 i=1

---- Math.random() ----
 d=0.4295173639976865 i=42

----  1st Random(1000) ----
b=true, d=0.46028809169559504, f=0.015927613, i1=169247282, i2=45, g=-0.719106498075259, l=-7363680848376404625, buf=[47, -38, 53, 63, -72, ]

----  2nd Random(1000) ----
b=true, d=0.46028809169559504, f=0.015927613, i1=169247282, i2=45, g=-0.719106498075259, l=-7363680848376404625, buf=[47, -38, 53, 63, -72, ]

----  1st Random() ----
b=true, d=0.35838511793470473, f=0.09502095, i1=1703847805, i2=5, g=-1.7843762893619448, l=4919551881815209453, buf=[118, 104, -2, 102, 14, ]

----  2nd Random() ----
b=false, d=0.26746716763904244, f=0.76336175, i1=-1087900062, i2=3, g=-0.9592892432531761, l=-1037301517667804861, buf=[27, 85, -18, 38, 126, ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

说明了要产生随机数都需要设置随机数种子,如果设置的是一样的话,每次获得的随机数是一样的。

# 实例2

问题:生成(-10,10)之间的保留小数点后两位数的随机数。

解决方法: 1.java中随机数生成函数Random r=new Random(); r.nextFloat();//生成(0,1)之间的浮点型随机数。将上述随机数乘以10,得到生成(0,10)之间的随机数。 2.生成一个Boolean型的随机数用于控制数的正负:r.nextBoolean(); 3.保留小数位数两位的方法:Math.floor(n*100+0.5)/100;得到的数为double型。

package randomTest;

import java.util.Random;

/**
 * 问题:生成(-10,10)之间的保留小数点后两位数的随机数。
 */
public class CreateRandom {
    public float numRandom() {
        float num;
        Random r = new Random();
        float value = (float) (Math.floor(r.nextFloat() * 1000 + 0.5) / 100);
        Boolean b = r.nextBoolean();
        if (b) {
            num = value;
        } else {
            num = 0 - value;
        }
        return num;
    }

    public static void main(String[] args) {
        CreateRandom cr = new CreateRandom();
        float num = cr.numRandom();
        System.out.print(num);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 实例3

Java生成随机无重复随机数,使用ArrayList实现

package randomTest;

import java.util.ArrayList;
import java.util.Random;

public class Demo3 {
    public static void main(String[] args) {
        int length = 50; // 50个随机数
        Random random = new Random();
        ArrayList<Integer> list = new ArrayList<Integer>();

        for (int i = 0; i < length; i++) {
            int number = random.nextInt(100) + 1; // 1-100的随机数(此处100必须比length大,否则会死循环)
            if (!list.contains(number)) {
                list.add(number);
            } else {
                i--; // 保证生成的随机数个数足够,防止有重复随机数时造成空位
            }
        }

        for (int i = 0; i < length; i++) {
            System.out.print(list.get(i) + "\t");

            if ((i + 1) % 10 == 0) {
                System.out.println("");
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 实例4

java生成固定位数的密码随机数代码

package randomTest;

import java.util.Random;

public class Demo4 {
   
    public static void main(String[] args) {
        System.out.println(genRandomNum(10));
    }

    /**
     * 生成随即密码
     *
     * @param pwd_len 生成的密码的总长度
     * @return 密码的字符串
     */
    public static String genRandomNum(int pwd_len) {
        // 35是因为数组是从0开始的,26个字母+10个数字
        final int maxNum = 36;
        int i; // 生成的随机数
        int count = 0; // 生成的密码的长度
        char[] str = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8',
                '9'};

        StringBuffer pwd = new StringBuffer("");
        Random r = new Random();
        while (count < pwd_len) {
            // 生成随机数,取绝对值,防止生成负数,

            i = Math.abs(r.nextInt(maxNum)); // 生成的数最大为36-1

            if (i >= 0 && i < str.length) {
                pwd.append(str[i]);
                count++;
            }
        }

        return pwd.toString();
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 实例5

Java生成带权重的随机数,A、B、C三个字符分别出现的概率是30%,40%,30%。

分析:首先1-100随机产生一个数,判断这个数,1-30出现的概率是30%, 31—70出现的概率是40%, 71-100出现的概率是30%

package randomTest;

import java.util.Random;

public class Demo6 {
    public static void main(String[] args) {
        int weight = new Random().nextInt(100);
        System.out.println("当前权重为:"+weight);
        if (weight <= 30) {
            System.out.println("A");
        } else if (weight >= 71) {
            System.out.println("C");
        }else{
            System.out.println("B");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

加深难度,如果存在n个字符,那么该如何实现呢?

package randomTest;

import java.util.*;

public class Demo7 {
    public static void main(String[] args) {
        //把字符权重用键值对保存
        Map<String, Integer> weightMap = new HashMap<String, Integer>();
        weightMap.put("A", 30);
        weightMap.put("B", 40);
        weightMap.put("C", 30);
        weightMap.put("S", 50);
        weightMap.put("G", 50);
        //遍历map,计算总权重
        Map<String, Integer> areaMap = new HashMap<String, Integer>();
        int total = 0;
        Set<Map.Entry<String, Integer>> entries = weightMap.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            int temp = total;
            Integer weight = entry.getValue();
            total += weight;
            // 设置权重范围,比如30,70,100
            areaMap.put(entry.getKey(), total);
            System.out.println(entry.getKey() + "的区间为[" + temp + "," + total + ")");
        }
        System.out.println("总权重为:" + total);
        //根据权重总数生成随机数
        int hit = new Random().nextInt(total);
        System.out.println("当成生成的随机数:" + hit);
        //遍历area,查看击中范围
        Set<Map.Entry<String, Integer>> areaEntries = areaMap.entrySet();
        for (Map.Entry<String, Integer> areaEntry : areaEntries) {
            Integer weight = areaEntry.getValue();
            //如果hit小于weight,则是命中
            if (hit < weight) {
                System.out.println("命中:" + areaEntry.getKey());
                break;
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
A的区间为[0,30)
B的区间为[30,70)
C的区间为[70,100)
S的区间为[100,150)
G的区间为[150,200)
总权重为:200
当成生成的随机数:115
命中:S
1
2
3
4
5
6
7
8

以后想要调增权重,只需要修改weightMap就行了,新来的选项,也可以放到weightMap里面

帮我改善此页面 (opens new window)
#Math#随机数#random#nextInt
上次更新: 2020/12/24, 04:18:38
其他类
枚举类

← 其他类 枚举类→

最近更新
01
zabbix学习笔记二
02-28
02
zabbix学习笔记一
02-10
03
Linux访问不了github
12-08
更多文章>
Theme by Vdoing | Copyright © 2020-2022 Saul.J.Wu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式