二.在java.util這個包里面提供了一個Random的類,我們可以新建一個Random的對象來產(chǎn)生隨機數(shù),他可以產(chǎn)生隨機整數(shù)、隨機float、隨機double,隨機long,這個也是我們在j2me的程序里經(jīng)常用的一個取隨機數(shù)的方法。
三.在我們的System類中有一個currentTimeMillis()方法,這個方法返回一個從1970年1月1號0點0分0秒到目前的一個毫秒數(shù),返回類型是long,我們可以拿他作為一個隨機數(shù),我們可以拿他對一些數(shù)取模,就可以把他限制在一個范圍之內(nèi)啦
此類的實例用于生成偽隨機數(shù)流,此類使用 48 位的種子,該種子可以使用線性同余公式對其進行修改(請參閱 Donald Knuth 的《The Art of Computer Programming, Volume 2》,第 3.2.1 節(jié))。
如果用相同的種子創(chuàng)建兩個 Random 實例,則對每個實例進行相同的方法調(diào)用序列,它們將生成并返回相同的數(shù)字序列。為了保證實現(xiàn)這種特性,我們?yōu)轭怰andom指定了特定的算法。為了 Java 代碼的完全可移植性,Java 實現(xiàn)必須讓類 Random 使用此處所示的所有算法。但是允許 Random 類的子類使用其他算法,只要其符合所有方法的常規(guī)協(xié)定即可。
(2) 如果沒有提供種子數(shù),Random實例的種子數(shù)將是當(dāng)前時間的毫秒數(shù),可以通過System.currentTimeMillis()來獲得當(dāng)前時間的毫秒數(shù)。打開JDK的源代碼,我們可以非常明確地看到這一點。
隨機數(shù)在實際中使用很廣泛,比如要隨即生成一個固定長度的字符串、數(shù)字。或者隨即生成一個不定長度的數(shù)字、或者進行一個模擬的隨機選擇等等。Java提供了最基本的工具,可以幫助開發(fā)者來實現(xiàn)這一切。
一、Java隨機數(shù)的產(chǎn)生方式
在Java中,隨機數(shù)的概念從廣義上將,有三種。
1、通過System.currentTimeMillis()來獲取一個當(dāng)前時間毫秒數(shù)的long型數(shù)字。
2、通過Math.random()返回一個0到1之間的double值。
3、通過Random類來產(chǎn)生一個隨機數(shù),這個是專業(yè)的Random工具類,功能強大。
二、Random類API說明
1、Java API說明
Random類的實例用于生成偽隨機數(shù)流。此類使用 48 位的種子,使用線性同余公式對其進行修改(請參閱 Donald Knuth 的《The Art of Computer Programming, Volume 2》,第 3.2.1 節(jié))。
如果用相同的種子創(chuàng)建兩個 Random 實例,則對每個實例進行相同的方法調(diào)用序列,它們將生成并返回相同的數(shù)字序列。為了保證屬性的實現(xiàn),為類 Random 指定了特定的算法。
很多應(yīng)用程序會發(fā)現(xiàn) Math 類中的 random 方法更易于使用。
2、方法摘要
Random()
創(chuàng)建一個新的隨機數(shù)生成器。
Random(long seed)
使用單個 long 種子創(chuàng)建一個新隨機數(shù)生成器: public Random(long seed) { setSeed(seed); } next 方法使用它來保存隨機數(shù)生成器的狀態(tài)。
protected int next(int bits)
生成下一個偽隨機數(shù)。
boolean nextBoolean()
返回下一個偽隨機數(shù),它是從此隨機數(shù)生成器的序列中取出的、均勻分布的 boolean 值。
void nextBytes(byte[] bytes)
生成隨機字節(jié)并將其置于用戶提供的字節(jié)數(shù)組中。
double nextDouble()
返回下一個偽隨機數(shù),它是從此隨機數(shù)生成器的序列中取出的、在 0.0 和 1.0之間均勻分布的 double 值。
float nextFloat()
返回下一個偽隨機數(shù),它是從此隨機數(shù)生成器的序列中取出的、在 0.0 和 1.0 之間均勻分布的 float 值。
double nextGaussian()
返回下一個偽隨機數(shù),它是從此隨機數(shù)生成器的序列中取出的、呈高斯(“正常地”)分布的 double 值,其平均值是 0.0,標(biāo)準(zhǔn)偏差是 1.0。
int nextInt()
返回下一個偽隨機數(shù),它是此隨機數(shù)生成器的序列中均勻分布的 int 值。
int nextInt(int n)
返回一個偽隨機數(shù),它是從此隨機數(shù)生成器的序列中取出的、在 0(包括)和指定值(不包括)之間均勻分布的 int值。
long nextLong()
返回下一個偽隨機數(shù),它是從此隨機數(shù)生成器的序列中取出的、均勻分布的 long 值。
void setSeed(long seed)
使用單個 long 種子設(shè)置此隨機數(shù)生成器的種子。
三、Random類使用說明
1、帶種子與不帶種子的區(qū)別Random類使用的根本是策略分帶種子和不帶種子的Random的實例。
通俗說,兩者的區(qū)別是:帶種子的,每次運行生成的結(jié)果都是一樣的。
不帶種子的,每次運行生成的都是隨機的,沒有規(guī)律可言。
2、創(chuàng)建不帶種子的Random對象
Random random = new Random();
3、創(chuàng)建不帶種子的Random對象有兩種方法:
1) Random random = new Random(555L);
2) Random random = new Random();random.setSeed(555L);
四、測試
通過一個例子說明上面的用法
import java.util.Random;
/**
* Java隨機數(shù)測試
* User: leizhimin
* Date: 2008-11-19 17:52:50
*/
public class TestRandomNum {
public static void main(String[] args) {
randomTest();
testNoSeed();
testSeed1();
testSeed2();
}
public static void randomTest() {
System.out.println("--------------test()--------------");
//返回以毫秒為單位的當(dāng)前時間。
long r1 = System.currentTimeMillis();
//返回帶正號的 double 值,大于或等于 0.0,小于 1.0。
double r2 = Math.random();
//通過Random類來獲取下一個隨機的整數(shù)
int r3 = new Random().nextInt();
System.out.println("r1 = " + r1);
System.out.println("r3 = " + r2);
System.out.println("r2 = " + r3);
}
public static void testNoSeed() {
System.out.println("--------------testNoSeed()--------------");
//創(chuàng)建不帶種子的測試Random對象
Random random = new Random();
for (int i = 0; i < 3; i++) {
System.out.println(random.nextInt());
}
}
public static void testSeed1() {
System.out.println("--------------testSeed1()--------------");
//創(chuàng)建帶種子的測試Random對象
Random random = new Random(555L);
for (int i = 0; i < 3; i++) {
System.out.println(random.nextInt());
}
}
public static void testSeed2() {
System.out.println("--------------testSeed2()--------------");
//創(chuàng)建帶種子的測試Random對象
Random random = new Random();
random.setSeed(555L);
for (int i = 0; i < 3; i++) {
System.out.println(random.nextInt());
}
}
}
運行結(jié)果:
--------------test()--------------
r1 = 1227108626582
r3 = 0.5324887850155043
r2 = -368083737
--------------testNoSeed()--------------
809503475
1585541532
-645134204
--------------testSeed1()--------------
-1367481220
292886146
-1462441651
--------------testSeed2()--------------
-1367481220
292886146
-1462441651
Process finished with exit code 0
通過testSeed1()與testSeed2()方法的結(jié)果可以看到,兩個打印結(jié)果相同,因為他們種子相同,再運行一次,結(jié)果還是一樣的,這就是帶種子隨機數(shù)的特性。
而不帶種子的,每次運行結(jié)果都是隨機的。
五、綜合應(yīng)用
下面通過最近寫的一個隨機數(shù)工具類來展示用法:
import java.util.Random;
/**
* 隨機數(shù)、隨即字符串工具
* User: leizhimin
* Date: 2008-11-19 9:43:09
*/
public class RandomUtils {
public static final String allChar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String letterChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String numberChar = "0123456789";
/**
* 返回一個定長的隨機字符串(只包含大小寫字母、數(shù)字)
*
* @param length 隨機字符串長度
* @return 隨機字符串
*/
public static String generateString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(allChar.charAt(random.nextInt(allChar.length())));
}
return sb.toString();
}
/**
* 返回一個定長的隨機純字母字符串(只包含大小寫字母)
*
* @param length 隨機字符串長度
* @return 隨機字符串
*/
public static String generateMixString(int length) {
StringBuffer sb = new StringBuffer();
Random random = new Random();
for (int i = 0; i < length; i++) {
sb.append(allChar.charAt(random.nextInt(letterChar.length())));
}
return sb.toString();
}
/**
* 返回一個定長的隨機純大寫字母字符串(只包含大小寫字母)
*
* @param length 隨機字符串長度
* @return 隨機字符串
*/
public static String generateLowerString(int length) {
return generateMixString(length).toLowerCase();
}
/**
* 返回一個定長的隨機純小寫字母字符串(只包含大小寫字母)
*
* @param length 隨機字符串長度
* @return 隨機字符串
*/
public static String generateUpperString(int length) {
return generateMixString(length).toUpperCase();
}
/**
* 生成一個定長的純0字符串
*
* @param length 字符串長度
* @return 純0字符串
*/
public static String generateZeroString(int length) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
sb.append('0');
}
return sb.toString();
}
/**
* 根據(jù)數(shù)字生成一個定長的字符串,長度不夠前面補0
*
* @param num 數(shù)字
* @param fixdlenth 字符串長度
* @return 定長的字符串
*/
public static String toFixdLengthString(long num, int fixdlenth) {
StringBuffer sb = new StringBuffer();
String strNum = String.valueOf(num);
if (fixdlenth - strNum.length() >= 0) {
sb.append(generateZeroString(fixdlenth - strNum.length()));
} else {
throw new RuntimeException("將數(shù)字" + num + "轉(zhuǎn)化為長度為" + fixdlenth + "的字符串發(fā)生異常!");
}
sb.append(strNum);
return sb.toString();
}
/**
* 根據(jù)數(shù)字生成一個定長的字符串,長度不夠前面補0
*
* @param num 數(shù)字
* @param fixdlenth 字符串長度
* @return 定長的字符串
*/
public static String toFixdLengthString(int num, int fixdlenth) {
StringBuffer sb = new StringBuffer();
String strNum = String.valueOf(num);
if (fixdlenth - strNum.length() >= 0) {
sb.append(generateZeroString(fixdlenth - strNum.length()));
} else {
throw new RuntimeException("將數(shù)字" + num + "轉(zhuǎn)化為長度為" + fixdlenth + "的字符串發(fā)生異常!");
}
sb.append(strNum);
return sb.toString();
}
public static void main(String[] args) {
System.out.println(generateString(15));
System.out.println(generateMixString(15));
System.out.println(generateLowerString(15));
System.out.println(generateUpperString(15));
System.out.println(generateZeroString(15));
System.out.println(toFixdLengthString(123, 15));
System.out.println(toFixdLengthString(123L, 15));
}
}
運行結(jié)果:
vWMBPiNbzfGCpHG
23hyraHdJkKPwMv
tigowetbwkm1nde
BPZ1KNEJPHB115N
000000000000000
000000000000123
000000000000123
Process finished with exit code 0
六、總結(jié)
1、隨機數(shù)很常用,在Java有三種產(chǎn)生方式,以Random隨機數(shù)的使用最為復(fù)雜。
2、Random類對象有是否帶種子之分,帶種子的只要種子相同,多次運行,生成隨機數(shù)的結(jié)果總是那樣。
3、帶種子隨機數(shù)的帶種子的對象創(chuàng)建方式有兩種,效果一樣。但是帶種子的隨機數(shù)用處似乎不大。
4、Random的功能涵蓋了Math.random()的功能。
5、可以通過隨機數(shù)去做實現(xiàn)隨機字符串等復(fù)雜的隨機數(shù)據(jù)。
6、不要研究不重復(fù)的隨機數(shù),意義不大。
在Java 中我們可以使用java.util.Random類來產(chǎn)生一個隨機數(shù)發(fā)生器。它有兩種形式的構(gòu)造函數(shù),分別是Random()和Random(long seed)。Random()使用當(dāng)前時間即System.currentTimeMillis()作為發(fā)生器的種子,Random(long seed)使用指定的seed作為發(fā)生器的種子。
隨機數(shù)發(fā)生器(Random)對象產(chǎn)生以后,通過調(diào)用不同的method:nextInt()、nextLong()、nextFloat()、nextDouble()等獲得不同類型隨機數(shù)。
1>生成隨機數(shù)
Random random = new Random();
Random random = new Random(100);//指定種子數(shù)100
random調(diào)用不同的方法,獲得隨機數(shù)。
如果2個Random對象使用相同的種子(比如都是100),并且以相同的順序調(diào)用相同的函數(shù),那它們返回值完全相同。如下面代碼中兩個Random對象的輸出完全相同
import java.util.*;
class TestRandom {
public static void main(String[] args) {
Random random1 = new Random(100);
System.out.println(random1.nextInt());
System.out.println(random1.nextFloat());
System.out.println(random1.nextBoolean());
Random random2 = new Random(100);
System.out.println(random2.nextInt());
System.out.println(random2.nextFloat());
System.out.println(random2.nextBoolean());
}
}
2>指定范圍內(nèi)的隨機數(shù)
隨機數(shù)控制在某個范圍內(nèi),使用模數(shù)運算符%
import java.util.*;
class TestRandom {
public static void main(String[] args) {
Random random = new Random();
for(int i = 0; i < 10;i++) {
System.out.println(Math.abs(random.nextInt())%10);
}
}
}
獲得的隨機數(shù)有正有負(fù)的,用Math.abs使獲取數(shù)據(jù)范圍為非負(fù)數(shù)
3>獲取指定范圍內(nèi)的不重復(fù)隨機數(shù)
import java.util.*;
class TestRandom {
public static void main(String[] args) {
int[] intRet = new int[6];
int intRd = 0; //存放隨機數(shù)
int count = 0; //記錄生成的隨機數(shù)個數(shù)
int flag = 0; //是否已經(jīng)生成過標(biāo)志
while(count<6){
Random rdm = new Random(System.currentTimeMillis());
intRd = Math.abs(rdm.nextInt())%32+1;
for(int i=0;i<count;i++){
if(intRet[i]==intRd){
flag = 1;
break;
}else{
flag = 0;
}
}
if(flag==0){
intRet[count] = intRd;
count++;
}
}
for(int t=0;t<6;t++){
System.out.println(t+"->"+intRet[t]);
}
}
}
Java中的隨機數(shù)是否可以重復(fù)?Java中產(chǎn)生的隨機數(shù)能否可以用來產(chǎn)生數(shù)據(jù)庫主鍵?帶著這個問題,我們做了一系列測試。
1.測試一: 使用不帶參數(shù)的Random()構(gòu)造函數(shù)
public class RandomTest {
public static void main(String[] args) {
java.util.Random r=new java.util.Random();
for(int i=0;i<10;i++){
System.out.println(r.nextInt());
}
}
}
程序運行結(jié)果:
-1761145445
-1070533012
216216989
-910884656
-1408725314
-1091802870
1681403823
-1099867456
347034376
-1277853157
再次運行該程序:
-169416241
220377062
-1140589550
-1364404766
-1088116756
2134626361
-546049728
1132916742
-1522319721
1787867608
從上面的測試我們可以看出,使用不帶參數(shù)的Random()構(gòu)造函數(shù)產(chǎn)生的隨機數(shù)不會重復(fù)。那么,什么情況下Java會產(chǎn)生重復(fù)的隨機數(shù)呢?且看下面的測試。
2. 測試二:為Random設(shè)置種子數(shù)
public class RandomTest_Repeat {
/**
* @param args
*/
public static void main(String[] args) {
java.util.Random r=new java.util.Random(10);
for(int i=0;i<10;i++){
System.out.println(r.nextInt());
}
}
}
無論程序運行多少次,其結(jié)果總是:
-1157793070
1913984760
1107254586
1773446580
254270492
-1408064384
1048475594
1581279777
-778209333
1532292428
甚至在不同的機器上測試,測試結(jié)果也不會改變!
3.原因分析:
(1) 首先請打開Java Doc,我們會看到Random類的說明:
此類的實例用于生成偽隨機數(shù)流,此類使用 48 位的種子,該種子可以使用線性同余公式對其進行修改(請參閱 Donald Knuth 的《The Art of Computer Programming, Volume 2》,第 3.2.1 節(jié))。
如果用相同的種子創(chuàng)建兩個 Random 實例,則對每個實例進行相同的方法調(diào)用序列,它們將生成并返回相同的數(shù)字序列。為了保證實現(xiàn)這種特性,我們?yōu)轭怰andom指定了特定的算法。為了 Java 代碼的完全可移植性,Java 實現(xiàn)必須讓類 Random 使用此處所示的所有算法。但是允許 Random 類的子類使用其他算法,只要其符合所有方法的常規(guī)協(xié)定即可。
Java Doc對Random類已經(jīng)解釋得非常明白,我們的測試也驗證了這一點。
(2) 如果沒有提供種子數(shù),Random實例的種子數(shù)將是當(dāng)前時間的毫秒數(shù),可以通過System.currentTimeMillis()來獲得當(dāng)前時間的毫秒數(shù)。打開JDK的源代碼,我們可以非常明確地看到這一點。
/**
* Creates a new random number generator. Its seed is initialized to
* a value based on the current time:
* <blockquote><pre>
* public Random() { this(System.currentTimeMillis()); }</pre></blockquote>
*
* @see java.lang.System#currentTimeMillis()
*/
public Random() { this(System.currentTimeMillis()); }
4. 結(jié)論:
通過上面的測試和分析,我們會對Random類有較為深刻的理解。同時,我覺得,通過閱讀Java Doc的API文檔,可以很好地提高我們的Java編程能力,做到“知其然”;一旦遇到費解的問題,不妨打開Java的源代碼,這樣我們就能做到“知其所以然”。