實(shí)例解析常用的java隨機(jī)數(shù)生成辦法

2022-04-22 14:28 更新

隨機(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ù)是如何生成的。


java隨機(jī)數(shù)

java產(chǎn)生隨機(jī)數(shù)的基本方法

方法一:在j2se里我們可以使用Math.random()方法來產(chǎn)生一個(gè)隨機(jī)數(shù),這個(gè)產(chǎn)生的隨機(jī)數(shù)是0-1之間的一個(gè)double,我們可以把他乘以一定的數(shù),比如說乘以100,他就是個(gè)100以內(nèi)的隨機(jī),這個(gè)在j2me中沒有。


(數(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


方法二:在java.util這個(gè)包里面提供了一個(gè)Random的類,我們可以新建一個(gè)Random的對(duì)象來產(chǎn)生隨機(jī)數(shù),他可以產(chǎn)生隨機(jī)整數(shù)、隨機(jī)float、隨機(jī)double,隨機(jī)long,這個(gè)也是我們?cè)趈2me的程序里經(jīng)常用的一個(gè)取隨機(jī)數(shù)的方法。

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ì)象相同。


Random類


3 、Random類使用示例
使用Random類,一般是生成指定區(qū)間的隨機(jī)數(shù)字,下面就一一介紹如何生成對(duì)應(yīng)區(qū)間的隨機(jī)數(shù)字。以下生成隨機(jī)數(shù)的代碼均使用以下Random對(duì)象r進(jìn)行生成:
Random r = new Random();
a 、生成[0,1.0)區(qū)間的小數(shù)
 double d1 = r.nextDouble();


直接使用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();


若要獲取int類型的整數(shù),只需要將上面的結(jié)果轉(zhuǎn)行成int類型即可。比如,獲取[0, 100)之間的int整數(shù)。方法如下:

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

實(shí)例學(xué)習(xí):

下面通過示例演示上面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("]");
  }

java

實(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;
	 }
}

















以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)