隨機(jī)數(shù)是任何一種編程語言最基本的特征之一,在技術(shù)開發(fā)中應(yīng)用很廣泛,因?yàn)橛袝r(shí)我們需要隨機(jī)生成一個(gè)固定長(zhǎng)度的數(shù)字、字符串亦或者是需要隨機(jī)生成一個(gè)不定長(zhǎng)度的數(shù)字、或者進(jìn)行一個(gè)模擬的隨機(jī)選擇等。Java就為我們提供了最基本的工具,可以幫助開發(fā)者生成不同條件下需要的隨機(jī)數(shù)。java中產(chǎn)生隨機(jī)數(shù)和c的差不多,一般有兩種隨機(jī)數(shù),一個(gè)是Math中random()方法,一個(gè)是Random類。不過不管是c還是java,要產(chǎn)生隨機(jī)數(shù)都需要設(shè)置隨機(jī)數(shù)種子,如果設(shè)置的是一樣的話,每次獲得的隨機(jī)數(shù)是一樣的。下面來匯總一下常見的不同類型的java隨機(jī)數(shù)是如何生成的。
(數(shù)據(jù)類型)(最小值+Math.random()*(最大值-最小值+1))
例1:從1到10的int型隨數(shù)
(int)(1+Math.random()*(10-1+1))
例2:
隨機(jī)生成0~100中的其中一個(gè)數(shù)
在上面我們已經(jīng)知道了Math.random()返回的只是從0到1之間的小數(shù),如果要50到100,就先放大50倍,即0到50之間,這里還是小數(shù),如果要整數(shù),就強(qiáng)制轉(zhuǎn)換int,然后再加上50即為50~100。
最終代碼:
(int)(Math.random()*50) + 50
Random random = new Random();//默認(rèn)構(gòu)造方法
Random random = new Random(1000);//指定種子數(shù)字
在進(jìn)行隨機(jī)時(shí),隨機(jī)算法的起源數(shù)字稱為種子數(shù)(seed),在種子數(shù)的基礎(chǔ)上進(jìn)行一定的變換,從而產(chǎn)生需要的隨機(jī)數(shù)字。
相同種子數(shù)的Random對(duì)象,相同次數(shù)生成的隨機(jī)數(shù)字是完全相同的。也就是說,兩個(gè)種子數(shù)相同的Random對(duì)象,第一次生成的隨機(jī)數(shù)字完全相同,第二次生成的隨機(jī)數(shù)字也完全相同。
例:獲取[0, 100)之間的int整數(shù)。
int i2 = random.nextInt(100);
Random 的函數(shù)接口:
// 構(gòu)造函數(shù)(一): 創(chuàng)建一個(gè)新的隨機(jī)數(shù)生成器。
Random()
// 構(gòu)造函數(shù)(二): 使用單個(gè) long 種子創(chuàng)建一個(gè)新隨機(jī)數(shù)生成器: public Random(long seed) { setSeed(seed); } next 方法使用它來保存隨機(jī)數(shù)生成器的狀態(tài)。
Random(long seed)
boolean nextBoolean() // 返回下一個(gè)“boolean類型”偽隨機(jī)數(shù)。
void nextBytes(byte[] buf) // 生成隨機(jī)字節(jié)并將其置于字節(jié)數(shù)組buf中。
double nextDouble() // 返回一個(gè)“[0.0, 1.0) 之間的double類型”的隨機(jī)數(shù)。
float nextFloat() // 返回一個(gè)“[0.0, 1.0) 之間的float類型”的隨機(jī)數(shù)。
int nextInt() // 返回下一個(gè)“int類型”隨機(jī)數(shù)。
int nextInt(int n) // 返回一個(gè)“[0, n) 之間的int類型”的隨機(jī)數(shù)。
long nextLong() // 返回下一個(gè)“l(fā)ong類型”隨機(jī)數(shù)。
synchronized double nextGaussian() // 返回下一個(gè)“double類型”的隨機(jī)數(shù),它是呈高斯(“正常地”)分布的 double 值,其平均值是 0.0,標(biāo)準(zhǔn)偏差是 1.0。
synchronized void setSeed(long seed) // 使用單個(gè) long 種子設(shè)置此隨機(jī)數(shù)生成器的種子。
Random類中的常用方法:
Random 類中的方法比較簡(jiǎn)單,每個(gè)方法的功能也很容易理解。需要說明的是,Random類中各方法生成的隨機(jī)數(shù)字都是均勻分布的,也就是說區(qū)間內(nèi)部的數(shù)字生成的幾率是均等的。下面對(duì)這些方法做一下基本的介紹:
a 、public boolean nextBoolean()
該方法的作用是生成一個(gè)隨機(jī)的boolean值,生成true和false的值幾率相等,也就是都是50%的幾率。
b 、public double nextDouble()
該方法的作用是生成一個(gè)隨機(jī)的double值,數(shù)值介于[0,1.0)之間,這里中括號(hào)代表包含區(qū)間端點(diǎn),小括號(hào)代表不包含區(qū)間端點(diǎn),也就是0到1之間的隨機(jī)小數(shù),包含0而不包含1.0。
c 、public int nextInt()
該方法的作用是生成一個(gè)隨機(jī)的int值,該值介于int的區(qū)間,也就是-2的31次方到2的31次方-1之間。
如果需要生成指定區(qū)間的int值,則需要進(jìn)行一定的數(shù)學(xué)變換,具體可以參看下面的使用示例中的代碼。
d 、public int nextInt(int n)
該方法的作用是生成一個(gè)隨機(jī)的int值,該值介于[0,n)的區(qū)間,也就是0到n之間的隨機(jī)int值,包含0而不包含n。
如果想生成指定區(qū)間的int值,也需要進(jìn)行一定的數(shù)學(xué)變換,具體可以參看下面的使用示例中的代碼。
e 、public void setSeed(long seed)
該方法的作用是重新設(shè)置Random對(duì)象中的種子數(shù)。設(shè)置完種子數(shù)以后的Random對(duì)象和相同種子數(shù)使用new關(guān)鍵字創(chuàng)建出的Random對(duì)象相同。
直接使用nextDouble方法獲得。
b、生成[0,5.0)區(qū)間的小數(shù)
double d2 = r.nextDouble() * 5;
因?yàn)閚extDouble方法生成的數(shù)字區(qū)間是[0,1.0),將該區(qū)間擴(kuò)大5倍即是要求的區(qū)間。
同理,生成[0,d)區(qū)間的隨機(jī)小數(shù),d為任意正的小數(shù),則只需要將nextDouble方法的返回值乘以d即可。
c、生成[1,2.5)區(qū)間的小數(shù) [n1,n2]
double d3 = r.nextDouble() * 1.5 + 1;【也就是 r.nextDouble() * (n2-n1)+n1】
生成[1,2.5)區(qū)間的隨機(jī)小數(shù),則只需要首先生成[0,1.5)區(qū)間的隨機(jī)數(shù)字,然后將生成的隨機(jī)數(shù)區(qū)間加1即可。
同理,生成任意非從0開始的小數(shù)區(qū)間[d1,d2)范圍的隨機(jī)數(shù)字(其中d1不等于0),則只需要首先生成[0,d2-d1)區(qū)間的隨機(jī)數(shù)字,然后將生成的隨機(jī)數(shù)字區(qū)間加上d1即可。
d、生成任意整數(shù)
int n1 = r.nextInt();
直接使用nextInt方法即可。
e、生成[0,10)區(qū)間的整數(shù)
int n2 = r.nextInt(10);
n2 = Math.abs(r.nextInt() % 10);
以上兩行代碼均可生成[0,10)區(qū)間的整數(shù)。
第一種實(shí)現(xiàn)使用Random類中的nextInt(int n)方法直接實(shí)現(xiàn)。
第二種實(shí)現(xiàn)中,首先調(diào)用nextInt()方法生成一個(gè)任意的int數(shù)字,該數(shù)字和10取余以后生成的數(shù)字區(qū)間為(-10,10),因?yàn)榘凑諗?shù)學(xué)上的規(guī)定余數(shù)的絕對(duì)值小于除數(shù),然后再對(duì)該區(qū)間求絕對(duì)值,則得到的區(qū)間就是[0,10)了。
同理,生成任意[0,n)區(qū)間的隨機(jī)整數(shù),都可以使用如下代碼:
int n2 = r.nextInt(n);
n2 = Math.abs(r.nextInt() % n);
f、生成[0,10]區(qū)間的整數(shù)
int n3 = r.nextInt(11);
n3 = Math.abs(r.nextInt() % 11);
相對(duì)于整數(shù)區(qū)間,[0,10]區(qū)間和[0,11)區(qū)間等價(jià),所以即生成[0,11)區(qū)間的整數(shù)。
g、生成[-3,15)區(qū)間的整數(shù)
int n4 = r.nextInt(18) - 3; 【也就是 r.nextInt() * (n2-n1)+n1】 n1是個(gè)負(fù)數(shù)
n4 = Math.abs(r.nextInt() % 18) - 3;
生成非從0開始區(qū)間的隨機(jī)整數(shù),可以參看上面非從0開始的小數(shù)區(qū)間實(shí)現(xiàn)原理的說明。
方法三:通過System.currentTimeMillis()來獲取一個(gè)當(dāng)前時(shí)間毫秒數(shù)的long型數(shù)字。
通過System.currentTimeMillis()來獲取隨機(jī)數(shù)。實(shí)際上是獲取當(dāng)前時(shí)間毫秒數(shù),它是long類型。使用方法如下:
final long l = System.currentTimeMillis();
final long l = System.currentTimeMillis();
final int i = (int)( l % 100 );
下面通過示例演示上面3種獲取隨機(jī)數(shù)的使用方法。 源碼如下(RandomTest.java):
import java.util.Random;
import java.lang.Math;
/**
* java 的隨機(jī)數(shù)測(cè)試程序。共3種獲取隨機(jī)數(shù)的方法:
* (01)、通過System.currentTimeMillis()來獲取一個(gè)當(dāng)前時(shí)間毫秒數(shù)的long型數(shù)字。
* (02)、通過Math.random()返回一個(gè)0到1之間的double值。
* (03)、通過Random類來產(chǎn)生一個(gè)隨機(jī)數(shù),這個(gè)是專業(yè)的Random工具類,功能強(qiáng)大。
*
* @author skywang
* @email kuiwu-wang@163.com
*/
public class RandomTest{
public static void main(String args[]){
// 通過System的currentTimeMillis()返回隨機(jī)數(shù)
testSystemTimeMillis();
// 通過Math的random()返回隨機(jī)數(shù)
testMathRandom();
// 新建“種子為1000”的Random對(duì)象,并通過該種子去測(cè)試Random的API
testRandomAPIs(new Random(1000), " 1st Random(1000)");
testRandomAPIs(new Random(1000), " 2nd Random(1000)");
// 新建“默認(rèn)種子”的Random對(duì)象,并通過該種子去測(cè)試Random的API
testRandomAPIs(new Random(), " 1st Random()");
testRandomAPIs(new Random(), " 2nd Random()");
}
/**
* 返回隨機(jī)數(shù)-01:測(cè)試System的currentTimeMillis()
*/
private static void testSystemTimeMillis() {
// 通過
final long l = System.currentTimeMillis();
// 通過l獲取一個(gè)[0, 100)之間的整數(shù)
final int i = (int)( l % 100 );
System.out.printf("\n---- System.currentTimeMillis() ----\n l=%s i=%s\n", l, i);
}
/**
* 返回隨機(jī)數(shù)-02:測(cè)試Math的random()
*/
private static void testMathRandom() {
// 通過Math的random()函數(shù)返回一個(gè)double類型隨機(jī)數(shù),范圍[0.0, 1.0)
final double d = Math.random();
// 通過d獲取一個(gè)[0, 100)之間的整數(shù)
final int i = (int)(d*100);
System.out.printf("\n---- Math.random() ----\n d=%s i=%s\n", d, i);
}
/**
* 返回隨機(jī)數(shù)-03:測(cè)試Random的API
*/
private static void testRandomAPIs(Random random, String title) {
final int BUFFER_LEN = 5;
// 獲取隨機(jī)的boolean值
boolean b = random.nextBoolean();
// 獲取隨機(jī)的數(shù)組buf[]
byte[] buf = new byte[BUFFER_LEN];
random.nextBytes(buf);
// 獲取隨機(jī)的Double值,范圍[0.0, 1.0)
double d = random.nextDouble();
// 獲取隨機(jī)的float值,范圍[0.0, 1.0)
float f = random.nextFloat();
// 獲取隨機(jī)的int值
int i1 = random.nextInt();
// 獲取隨機(jī)的[0,100)之間的int值
int i2 = random.nextInt(100);
// 獲取隨機(jī)的高斯分布的double值
double g = random.nextGaussian();
// 獲取隨機(jī)的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("]");
}
實(shí)例2:
問題:生成(-10,10)之間的保留小數(shù)點(diǎn)后兩位數(shù)的隨機(jī)數(shù)。
解決方法:
1.java中隨機(jī)數(shù)生成函數(shù)Random r=new Random(); r.nextFloat();//生成(0,1)之間的浮點(diǎn)型隨機(jī)數(shù)。將上述隨機(jī)數(shù)乘以10,得到生成(0,10)之間的隨機(jī)數(shù)。
2.生成一個(gè)Boolean型的隨機(jī)數(shù)用于控制數(shù)的正負(fù):r.nextBoolean();
3.保留小數(shù)位數(shù)兩位的方法:Math.floor(n*100+0.5)/100;得到的數(shù)為double型。
代碼如下:
import java.util.*;
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);
}
}
實(shí)例3:
Java生成隨機(jī)無重復(fù)隨機(jī)數(shù),使用ArrayList實(shí)現(xiàn)
import java.util.ArrayList;
import java.util.Random;
/**
* 生成隨機(jī)無重復(fù)隨機(jī)數(shù),使用ArrayList實(shí)現(xiàn)
*
* 算法:加入隨機(jī)數(shù)時(shí)檢測(cè)列表中是否已存在此隨機(jī)數(shù),有則重來,無則加入。
*
*/
public class Demo {
public static void main(String[] args) {
int length = 50; // 50個(gè)隨機(jī)數(shù)
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的隨機(jī)數(shù)(此處100必須比length大,否則會(huì)死循環(huán))
if (!list.contains(number)) {
list.add(number);
} else {
i--; // 保證生成的隨機(jī)數(shù)個(gè)數(shù)足夠,防止有重復(fù)隨機(jī)數(shù)時(shí)造成空位
}
}
for (int i = 0; i < length; i++) {
System.out.print(list.get(i) + "\t");
if ((i + 1) % 10 == 0) {
System.out.println("");
}
}
}
}
實(shí)例4:
java生成固定位數(shù)的密碼隨機(jī)數(shù)代碼
public class RandomPassword {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println(genRandomNum(10));
}
/**
* 生成隨即密碼
*
* @param pwd_len
* 生成的密碼的總長(zhǎng)度
* @return 密碼的字符串
*/
public static String genRandomNum(int pwd_len) {
// 35是因?yàn)閿?shù)組是從0開始的,26個(gè)字母+10個(gè)數(shù)字
final int maxNum = 36;
int i; // 生成的隨機(jī)數(shù)
int count = 0; // 生成的密碼的長(zhǎng)度
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) {
// 生成隨機(jī)數(shù),取絕對(duì)值,防止生成負(fù)數(shù),
i = Math.abs(r.nextInt(maxNum)); // 生成的數(shù)最大為36-1
if (i >= 0 && i < str.length) {
pwd.append(str[i]);
count++;
}
}
return pwd.toString();
}
}
實(shí)例5:
Java生成帶權(quán)重的隨機(jī)數(shù)
package test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
//帶權(quán)重的隨機(jī)數(shù)
//面試的時(shí)候面試官問道一個(gè)這樣的問題
//A、B、C三個(gè)字符分別出現(xiàn)的概率是30%,40%,30%
//分析:首先1-100隨機(jī)產(chǎn)生一個(gè)數(shù),判斷這個(gè)數(shù),1-30出現(xiàn)的概率是30%, 31—70出現(xiàn)的概率是40%, 71-100出現(xiàn)的概率是30%
public class WeightRandom {
public static void main(String[] args) {
Random ran = new Random();
String str=getWanfei(ran.nextInt(100));
Map<String,Object> map = new HashMap<String,Object>();
map.put("key","A");
map.put("value","30");
Map<String,Object> map1 = new HashMap<String,Object>();
map.put("key","B");
map.put("value","70");
List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
list.add(map);
list.add(map1);
System.out.println( getWeight(list,ran.nextInt(100)));
}
//知道權(quán)重的情況下
public static String getWanfei(int num){
if(num>=1 && num<=30){
return "A";
}else if(num>=31 && num<70){
return "B";
}else{
return "C";
}
}
//如果A、B、C的個(gè)數(shù)不確定 ,權(quán)重的總數(shù)也也不確定
public static String getWeight(List<Map<String,Object>> list,int ran){
//map里放的是a,b,c 值,和每個(gè)a、b、c對(duì)應(yīng)的權(quán)重
int sum=0;
int total = list.size();
for(int i=0;i<total;i++){
sum+=Integer.parseInt(list.get(i).get("value").toString());
if(ran<=sum){
return list.get(i).get("key").toString();
}
}
return null;
}
}
更多建議: