原文章:
一、java中获取随机数、随机字符串常用方法 http://blog.csdn.net/cndmss/article/details/51996876(本文所转)
二、java生成指定范围的随机数 http://blog.csdn.net/u013905744/article/details/73480674
一、前言
在日常工作当中,经常会有需要获取随机数、随机字符的需求,如:生成随机数验证码、生成随机字符串签名、生成2个数字之间的随机数等。这些场景其根本都在于随机数的生成,本文将对java当中生成随机数、随机字符等常见应用场景及获取方法进行简单小结。
二、伪随机、真随机数简介
计算机很难产生真正意义上的 真随机数,通常我们所说的产生随机数,都是指 伪随机数。从一定意义上来说,计算机本身几乎是不可能产生真正意义上的真随机数的,因为其一定是按照一定的运算规则来获取随机数的;当然,伪随机数的 伪并不是说这个随机数就是假的,而是指,这个生成的随机数是按指定规律运算出来的 相对随机的一个数。这些规律就是指各种编程语言中生成随机数的算法,java当中用的算法之一是 线性同余算法。(具体介绍请参考 http://t1174779123.iteye.com/blog/2037719)三、Java本身的生成随机数相关方法简介
Java本身有2个常用的类来生成随机数,一个是直接使用 java.lang.Math类中的 Math.random()方法获取一个 [0.0,1.0)之间的一个double类型的随机数;另一个是通过 java.util.Random类,创建一个随机数发生器,然后再生成随机数。通过查看源码可以发现,Math.random()本身其实也是通过java.util.Random类来实现生成随机数的,只是说,其使用起来更加简单方便。- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
1、Math.random()
Java中的 java.lang.Math类包含常见的一些数学公式函数,如:Math.round(n)四舍五入取整,Math.sqrt(n)计算平方根,Math.abs(n)计算绝对值等;而Math.random()函数则是获取一个[0.0,1.0)之间一个double类型的 伪随机数。通过Math.random()获取一个[0.0,1.0)之间的随机数后,我们就可以通过简单运算获取值在[m,n)之间的随机数了; 如: Math.random()*10就可以获取一个[0.0,10.0)之间的一个随机数,Math.random()*10+5就可以获取一个[5.0,15.0)之间的一个随机数,然后将获取的随机数进行数据类型转换就可以获取我们最终所需的随机数。
获取公式:(条件:0<=m<=n)
[m,n)之间: (数据类型)(m+Math.random()*(n-m));
[m,n]之间: (数据类型)(m+Math.random()*(n-m+1));
2、java.util.Random类
Java中的java.util.Random类可以创建一个随机数发生器,其构造函数有2个,分别是 Random()、 Random(long seed),前一个是创建不指定 种子的随机数生成器,后一个是创建指定种子的随机数生成器,然后通过生成器生成随机数。种子,指生成随机数算法的起始数字,和生成的随机数的区间没有任何关系。Random()构造函数其实默认会指定种子,老版本的JDK用的是 System.currentTimeMillis()方法获取当前计算机时间作为种子,而新版本的JDK用的是 System.nanoTime()方法获取当前cpu核心纳秒级时间作为种子。(两者区别请参考 http://blog.csdn.net/dliyuedong/article/details/8806868)
- 1
- 2
- 3
- 4
指定种子的话,如果种子值相同,无论执行多少次,其将生成同一随机数列。
例1:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
无论执行多少次,其输出结果均为:
- 1
- 2
- 3
- 4
Random类中有许多生成随机数的方法,如Math.random()其实就是调用Random类中的nextDouble()方法来获取随机数。这里对其中常用的方法简单说明一下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
基本上有以上常用方法,就可以通过简单运算获取我们最终所需的随机数了,运算方法可以参考第1点说明;当然,Random类还有其它获取随机数的方法,感兴趣的朋友可以去了解一下。
四、常见的随机数使用场景及生成方法
(注意值的闭包区间)1、获取指定数值内的随机数
例2:- 1
- 2
- 3
- 4
2、获取2个数字区间内的随机数
例3:- 1
- 2
- 3
- 4
此方法可用于生成随机验证码。
3、获取指定长度的随机字符串
Java本身并没有生成随机字符串的方法,但我们可以通过java自带的随机数方法运算获取所需的随机字符串。例4:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
在这个例子中,我们先自定义一个字符串库KeyString ,然后通过Math.random()方法获取KeyString长度内的一个随机数,接着再获取该随机数对应KeyString中相应位置的一个字符,最后将随机获取并组装好的字符串返回。
大家可以发现,这个例子获取的随机字符串可能包含小写字母、大写字母、数字;如果说还需要包含其它字符的话,如%、#、/、* 等特殊字符,只需将相应字符添加到字符串库KeyString 中去即可;同理,若想生成只包含小写字母或者只包含数字的字符串,也只需修改字符串库KeyString 即可。可以说,这几乎是获取随机字符串的一个“万金油”方法。
4、随机生成指定概率的数字
获取指定值内的随机数,从理论上来说,每个数字出现概率都是一样的,但是,我们可以通过一定的运算实现按一定的概率获取数字。如:我们想随机生成0、1这两个数字,但是呢,我们希望0出现的概率为70%,1出现的概率为30%;这个时候,我们可以通过用一定的随机数区间值来分别表示0、1,从而实现按概率获取随机数。
例5:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
由以上示例可知,通过一定的运算,我们就可以按一定概率获取数字,非常简单的抽奖小游戏就可以使用这种方式来设置中奖概率。
例6:
- 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
需要指出的是,这只是一个非常简单的小示例,只适用于要求较低的场景。真正严格意义上的抽奖有许多要求,如总出奖数量、每个奖的概率随时间的推移而变化等,有专门的一些算法去实现抽奖中的各种概率问题,感兴趣的朋友可以去了解一下。
五、总结
1、Math.random()方法和Random类获取随机数的实现方法相同,只是相对而言,Math.random()的使用更简洁便利,而Random类的方法更丰富、使用更加灵活。2、高并发系统中,即使种子为毫秒级,java.util.Random类获取的随机数,还是可能会相同,从而给系统带来潜在风险。
3、随机数是相对随机的,伪随机数生成效率高,而真随机数可能需要一定的硬件支持且生成效率低;并没有说哪个就一定好,凡事都有相对性,我们可以根据自己业务场景所需选择。