您的位置:首页 > 编程语言 > Java开发

Java随机数

2016-03-29 10:16 477 查看
本章先讲解Java随机数的几种产生方式,然后通过示例对其进行演示。

广义上讲,Java中的随机数的有三种产生方式
(01).通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字。
(02).通过Math.random()返回一个0到1之间的double值。
(03).通过Random类来产生一个随机数,这个是专业的Random工具类,功能强大。

[b]第1种[/b]

通过System.currentTimeMillis()来获取随机数。实际上是获取当前时间毫秒数,它是long类型。使用方法如下:

finallongl=System.currentTimeMillis();


若要获取int类型的整数,只需要将上面的结果转行成int类型即可。比如,获取[0,100)之间的int整数。方法如下:

finallongl=System.currentTimeMillis();
finalinti=(int)(l%100);


[b]第2种[/b]

通过Math.random()来获取随机数。实际上,它返回的是0(包含)到1(不包含)之间的double值。使用方法如下:

finaldoubled=Math.random();


若要获取int类型的整数,只需要将上面的结果转行成int类型即可。比如,获取[0,100)之间的int整数。方法如下:

finaldoubled=Math.random();
finalinti=(int)(d*100);


Math.random();方法执行的本质是调用Random.nextDouble()方法;这里来看一个Math.random()的源码:

privatestaticRandomrandomNumberGenerator;//定义一个Random的私有的静态的变量
//对Random进行初始化操作
privatestaticsynchronizedRandominitRNG(){
Randomrnd=randomNumberGenerator;
return(rnd==null)?(randomNumberGenerator=newRandom()):rnd;
}


publicstaticdoublerandom(){
Randomrnd=randomNumberGenerator;
if(rnd==null)rnd=initRNG();
returnrnd.nextDouble();
}
对上述源码进行简单解析:首先定义一个privatestatic的Random变量,这样所有的Math对象都可以共享这个类变量,而且只用初始化一次就可以,
    执行random()方法的时候,首先判断类random变量是否已经被赋值,如果为null,则进行初始化操作,(初始化过程用Synchronized进行同步,适用于多线程环境);
    如果对象不为null,说明已经完成了初始化操作,那么直接调用random的nextDouble()方法。
如果只涉及到单线程的话,这个操作等价于Randomrandom=newRandom();returnrandom.nextDouble();


[b]第3种[/b]

通过Random类来获取随机数。

使用方法如下:
(01)创建Random对象。有两种方法可以创建Random对象,如下:

Randomrandom=newRandom();//默认构造方法
Randomrandom=newRandom(1000);//指定种子数字


(02)通过Random对象获取随机数。Random支持的随机值类型包括:boolean,byte,int,long,float,double。
比如,获取[0,100)之间的int整数。方法如下:

inti2=random.nextInt(100);


[b]Random的函数接口[/b]

//构造函数(一):创建一个新的随机数生成器。
Random()
//构造函数(二):使用单个long种子创建一个新随机数生成器:publicRandom(longseed){setSeed(seed);}next方法使用它来保存随机数生成器的状态。
Random(longseed)

booleannextBoolean()//返回下一个“boolean类型”伪随机数。
voidnextBytes(byte[]buf)//生成随机字节并将其置于字节数组buf中。
doublenextDouble()//返回一个“[0.0,1.0)之间的double类型”的随机数。
floatnextFloat()//返回一个“[0.0,1.0)之间的float类型”的随机数。
intnextInt()//返回下一个“int类型”随机数。
intnextInt(intn)//返回一个“[0,n)之间的int类型”的随机数。
longnextLong()//返回下一个“long类型”随机数。
synchronizeddoublenextGaussian()//返回下一个“double类型”的随机数,它是呈高斯(“正常地”)分布的double值,其平均值是0.0,标准偏差是1.0。
synchronizedvoidsetSeed(longseed)//使用单个long种子设置此随机数生成器的种子。


接口源码实现:

//最基本的方法,所有的随机数生成方法都调用了他,同时可以看到,Random采用的种子是AtomicLong类型的原子类,next方法来进行求解的时候使用了CAS机制保证了操作的原子类与线程安全性

protectedintnext(intbits){
longoldseed,nextseed;
AtomicLongseed=this.seed;
do{
oldseed=seed.get();
nextseed=(oldseed*multiplier+addend)&mask;
}while(!seed.compareAndSet(oldseed,nextseed));
return(int)(nextseed>>>(48-bits));
}

//nextInt()调用了next(32)方法

publicintnextInt(){
returnnext(32);
}


//nextInt(n)调用了next(31)方法,然后对n取余,这样就可以求得[0,n)之内的随机数了
publicintnextInt(intn){
if(n<=0)
thrownewIllegalArgumentException("nmustbepositive");

if((n&-n)==n)//i.e.,nisapowerof2
return(int)((n*(long)next(31))>>31);

intbits,val;
do{
bits=next(31);
val=bits%n;
}while(bits-val+(n-1)<0);
returnval;
}

//调用了next(32),然后左移32位,在加上next(32)
publiclongnextLong(){
//it'sokaythatthebottomwordremainssigned.
return((long)(next(32))<<32)+next(32);
}

//调用了next(1),判断结果是否是0来生成true还是false
publicbooleannextBoolean(){
returnnext(1)!=0;
}


//调用了next(24)
publicfloatnextFloat(){
returnnext(24)/((float)(1<<24));
}

//调用了next(26)与next(27)

publicdoublenextDouble(){
return(((long)(next(26))<<27)+next(27))
/(double)(1L<<53);
}

note:Random是线程安全的,用AtomicLong原子类以及CAS机制保证了操作的原子性,在进行种子设置的时候采用synchronized保证了操作的同步性,
    但是多线程环境中,不建议采用Random方法,影响性能,建议采用java.util.concurrent.ThreadLocalRandom类,如果强调加密的安全性,
    建议使用java.security.SecureRandom.


[b]获取随机数示例[/b]

下面通过示例演示上面3种获取随机数的使用方法。
源码如下(RandomTest.java):

1importjava.util.Random;
2importjava.lang.Math;
3
4/**
5*java的随机数测试程序。共3种获取随机数的方法:
6*(01)、通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型数字。
7*(02)、通过Math.random()返回一个0到1之间的double值。
8*(03)、通过Random类来产生一个随机数,这个是专业的Random工具类,功能强大。
9*
10*@authorskywang
11*@emailkuiwu-wang@163.com
12*/
13publicclassRandomTest{
14
15publicstaticvoidmain(Stringargs[]){
16
17//通过System的currentTimeMillis()返回随机数
18testSystemTimeMillis();
19
20//通过Math的random()返回随机数
21testMathRandom();
22
23//新建“种子为1000”的Random对象,并通过该种子去测试Random的API
24testRandomAPIs(newRandom(1000),"1stRandom(1000)");
25testRandomAPIs(newRandom(1000),"2ndRandom(1000)");
26//新建“默认种子”的Random对象,并通过该种子去测试Random的API
27testRandomAPIs(newRandom(),"1stRandom()");
28testRandomAPIs(newRandom(),"2ndRandom()");
29}
30
31/**
32*返回随机数-01:测试System的currentTimeMillis()
33*/
34privatestaticvoidtestSystemTimeMillis(){
35//通过
36finallongl=System.currentTimeMillis();
37//通过l获取一个[0,100)之间的整数
38finalinti=(int)(l%100);
39
40System.out.printf("\n----System.currentTimeMillis()----\nl=%si=%s\n",l,i);
41}
42
43
44/**
45*返回随机数-02:测试Math的random()
46*/
47privatestaticvoidtestMathRandom(){
48//通过Math的random()函数返回一个double类型随机数,范围[0.0,1.0)
49finaldoubled=Math.random();
50//通过d获取一个[0,100)之间的整数
51finalinti=(int)(d*100);
52
53System.out.printf("\n----Math.random()----\nd=%si=%s\n",d,i);
54}
55
56
57/**
58*返回随机数-03:测试Random的API
59*/
60privatestaticvoidtestRandomAPIs(Randomrandom,Stringtitle){
61finalintBUFFER_LEN=5;
62
63//获取随机的boolean值
64booleanb=random.nextBoolean();
65//获取随机的数组buf[]
66byte[]buf=newbyte[BUFFER_LEN];
67random.nextBytes(buf);
68//获取随机的Double值,范围[0.0,1.0)
69doubled=random.nextDouble();
70//获取随机的float值,范围[0.0,1.0)
71floatf=random.nextFloat();
72//获取随机的int值
73inti1=random.nextInt();
74//获取随机的[0,100)之间的int值
75inti2=random.nextInt(100);
76//获取随机的高斯分布的double值
77doubleg=random.nextGaussian();
78//获取随机的long值
79longl=random.nextLong();
80
81System.out.printf("\n----%s----\nb=%s,d=%s,f=%s,i1=%s,i2=%s,g=%s,l=%s,buf=[",
82title,b,d,f,i1,i2,g,l);
83for(bytebt:buf)
84System.out.printf("%s,",bt);
85System.out.println("]");
86}
87}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: