Java随机数生成Random类
- Random类
java.Util.Random类,此类的一个实例用于生成伪随机数流,如果使用相同的种子创建了两个Random实例,并且对每个实例进行了相同的方法调用序列,则它们将生成并返回相同的数字序列。
java.util.Random 的实例是线程安全的。但是,在多个线程中并发使用同一个java.util.Random实例可能会遇到争用问题,从而导致性能不佳。可以考虑在多线程设计中使用java.util.concurrent.ThreadLocalRandom类。
java.util.Random的实例在加密方面并不安全。可以考虑使用java.security.SecureRandom来获取加密安全的伪随机数生成器,以供安全敏感的应用程序使用。
- 构造方法
- public Random()
创建一个新的随机数生成器。此构造函数将随机生成一个种子,它的值很可能与此构造函数的其他任何调用者使用的值都不相同(确保种子的唯一性)。
- public Random(long seed)
使用单个长种子创建新的随机数生成器。种子是由next方法维护的伪随机数生成器内部状态的初始值。
调用 new Random(seed) 等同于:
Randomrnd = new Random();
rnd.setSeed(seed);
常提供的seed有:
System.currentTimeMillis(); //本机当前的毫秒值
System.nanoTime(); //本机当前的纳秒值
如果使用相同的种子创建了两个 Random 实例,并且对每个实例进行了相同的方法调用序列,则它们将生成并返回相同的数字序列。如下两个Random的对象r1和r2使用相同的seed,故它们生成的随机数是一样的,代码:
public class RandDemo {
public static void main(String[] args) {
// 系统当前毫秒值,也可用System.nanoTime()
long seed = System.currentTimeMillis();
// 创建Random对象r1
Random r1 = new Random(seed);
// 创建Random对象r2
Random r2 = new Random(seed);
// r1和r2生成10个相同的伪随机数
for (int i = 0; i < 3; i++) {
System.out.println("======第" + (i + 1) + "次======");
System.out.println(r1.nextInt());
System.out.println(r2.nextInt());
}
/* 笔者在运行这段代码时的输出:
======第1次======
-1705500708
-1705500708
======第2次======
1375764432
1375764432
======第3次======
-2111979661
-2111979661
*/
}
}
所以,要知晓Random对象的伪随机特性,随机只是表明调用随机方法时生成的数是按相等概率分布的,并不代表不能被预测,否则就是真随机数了,而这在计算机里是做不到的。
- 常用方法
- public int nextInt()
此方法返回此随机数生成器序列中的下一个伪随机均匀分布的int值。nextInt的一般约定是生成并返回一个int值。
返回值:这个随机数生成器序列中的下一个伪随机均匀分布的int值,即int范围内的任一随机数。
- public int nextInt(int bound)
返回一个伪随机、均匀分布的整数值,该值在0(包括)和指定值bound(不包括)之间,从该随机数生成器的序列中抽取。nextInt的通用约定是,在指定范围内,一个int值是伪随机生成并返回的。所有可能的 int 值都是以(近似)相等的概率产生的。
参数:bound – 上限(不包括上限)。必须为正数。
范围值:下一个伪随机、均匀分布的整数值,介于此随机数生成器序列的零(包括)和边界(不包括)之间
举例:
Random r = new Random();
// 生成一个0-100的整数值
int randNum1 = r.nextInt(101);
// 生成一个1-100之间的整数值
int randNum2 = r.nextInt(100) + 1;
System.out.println(randNum1);
System.out.println(randNum2);
此外还有nextLong()、nextBoolean()、nextFloat()、nextDouble()方法。
- Math.random()方法
java.lang.Math.random()方法,其本质就是调用Random类的nextDouble()方法。
本方法返回一个带有正号的双精度值,大于或等于0.0(包含)并小于1.0(不包含)。返回的值是(近似)均匀分布在该范围内的伪随机值。
当首次调用此方法时,它会创建一个新的伪随机数生成器,如下:
new java.util.Random()
此后,此新的伪随机数生成器用于对此方法的所有调用,并且不用于其他任何地方。
此方法已正确同步,允许多个线程正确使用。但是,(由于底层就是使用Random类,所以其特性与Random一样)如果许多线程需要以极高的速率生成伪随机数,则每个线程拥有自己的伪随机数生成器可能会减少争用,此时应考虑使用java.util.concurrent.ThreadLocalRandom类。
- 应用
返回指定范围的随机数min(包含)到max(不包含)之间的公式:
Math.random() * (max-min) + min;
如下示例方法:
public class RandDemo2 {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
//System.out.println(getRandom());
//System.out.println(getRandomArbitrary(0, 100));
//System.out.println(getRandomInt(0, 100));
//System.out.println(getRandomIntInclusive(1, 100));
//System.out.println(getRandomLowercaseLetter());
System.out.println(getRandomVisibleCharacter());
}
}
/**
* 得到一个大于等于 0,小于 1 之间的随机double类型的数
* @return 返回[0,1)之间的一个随机double值
*/
public static double getRandom() {
return Math.random();
}
/**
* 得到一个两数之间的随机数
* 这个例子返回了一个在指定值之间的随机数。
* 这个值在 min(包含)与max(不包含)之间。
* @param min 下区间(包含)
* @param max 上区间(不包含)
* @return 返回[min,max)区间内的double值
*/
public static double getRandomArbitrary(int min, int max) {
return (Math.random() * (max - min) + min);
}
/**
* 这个例子返回了一个在指定值之间的随机整数。
* 这个值不小于 min (包含),且小于(不包含)max。
* @param min 下区间(包含)
* @param max 上区间(不包含)
* @return 在[min,max)区间内的随机整数
*/
public static int getRandomInt(int min, int max) {
return (int) (Math.floor(Math.random() * (max - min)) + min); //不含最大值,含最小值
}
/**
* 上一个例子提到的函数 getRandomInt() 结果范围包含了最小值,但不含最大值。
* 如果你的随机结果需要同时包含最小值和最大值,怎么办呢?
* getRandomIntInclusive() 函数可以实现。
* @param min 下区间(包含)
* @param max 上区间(不包含)
* @return 在[min,max]区间内的随机整数
*/
public static int getRandomIntInclusive(int min, int max) {
return (int) (Math.floor(Math.random() * (max - min + 1)) + min); //含最大值,含最小值
}
/**
* 生成一个ASCII码表中随机小写字母,a-z之间
* @return 生成一个随机字符a-z之间
*/
public static char getRandomLowercaseLetter(){
return (char) (Math.random() * ('z' - 'a' + 1) + 'a');
}
/**
* 生成一个ASCII码表中的!到~之间的可见字符
* @return 生成一个ASCII码表中的!到~之间的可见字符
*/
public static char getRandomVisibleCharacter(){
return (char) (Math.random() * ('~' - '!' + 1) + '!');
}
}