Java随机数

15 篇文章 0 订阅

为什么说Java中的随机数都是伪随机数?

什么是伪随机数?
   1.伪随机数是看似随机实质是固定的周期性序列,也就是有规则的随机。
  2.只要这个随机数是由确定算法生成的,那就是伪随机,只能通过不断算法优化,使你的随机数更接近随机。
   (随机这个属性和算法本身就是矛盾的)
  3.通过真实随机事件取得的随机数才是真随机数。

Java随机数产生方式:

1,使用Math.random()方法来产生一个随机数,这个产生的随机数是0-1之间的一个double,我们可以把他乘以一定的数,比如说乘以100,他就是个100以内的随机。

System.out.println(Math.random());

2,在java.util这个包里面提供了一个Random的类,我们可以新建一个Random的对象来产生随机数,他可以产生随机整数、随机float、随机double,随机long。

        Random random=new Random();
        System.out.println(random.nextInt(1000));
        System.out.println(random.nextDouble());

3,在我们的System类中有一个currentTimeMillis()方法,这个方法返回一个从1970年1月1号0点0分0秒到目前的一个毫秒数,返回类型是long,我们可以拿他作为一个随机数,我们可以拿他对一些数取模,就可以取得随机数,类似的System类还有nanoTime()方法,返回纳秒级时间。

        System.out.println(System.currentTimeMillis());
        System.out.println(System.nanoTime());

需要说明的是:

java.Math.Random()实际是在内部调用java.util.Random()的:

以下Math.class的源码,可见Math是基于一个java.util.Random单例的。

public static double random() {
        return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
    }
private static final class RandomNumberGeneratorHolder {
        static final Random randomNumberGenerator = new Random();
    }

Random有两种构造方法:

  Random():使用一个和当前系统时间对应的相对时间有关的数字作为种子数。

  Random(long seed):直接传入一个种子数。

种子的作用是什么?

  种子就是产生随机数的第一次使用值,机制是通过一个函数,将这个种子的值转化为随机数空间中的某一个点上,并且产生的随机数均匀的散布在空间中。以后产生的随机数都与前一个随机数有关。

举例:

        Random r1 = new Random();
        Random r2 = new Random();
        //无参构造使用的是参数作为种子数
        Random r3 = new Random(100);
        Random r4 = new Random(100);
        //产生随机数调用nextXXX()方法
        System.out.println(r1.nextInt(10));
        System.out.println(r1.nextInt(10));
        System.out.println(r2.nextInt(10));
        System.out.println(r2.nextInt(10));
        System.out.println("-----------------");
        System.out.println(r3.nextInt(10));        
        System.out.println(r3.nextInt(10));
        System.out.println(r4.nextInt(10));
        System.out.println(r4.nextInt(10));

结果:

5
1
4
0
-----------------
5
0
5
0

r3,r4产生的随机数序列是相同的。

Java自带的随机数函数是很容易被黑客破解的,因为黑客可以通过获取一定长度的随机数序列来推出你的seed,然后就可以预测下一个随机数。程序员可以自己编写随机数生成算法并不断优化,安全性会得到提高。

这里给出一个自编的随机数生成方法:

 static double rand(double[] seed){//注意传入参数是一个数组类型
        double base=256.0;
        double u=16.0;
        double v=123.2;

        double temp1,temp2,temp3;
        temp1=u*seed[0]+v;
        temp2=(int)(temp1/base);
        temp3=temp1-temp2*base;
        seed[0]=temp3;
        double random=seed[0]/base;
        return random;
    }
 public static void main(String[] args) {
        double[] seed={5.0};//必须使用数组传入,因为必须要传地址,才能改变在内存中的值,如果只传入一个double类型,生成出来将始终是一个数
        System.out.println(rand(seed));
        System.out.println(rand(seed));
        System.out.println(rand(seed));
        System.out.println(rand(seed));

    }

无论是JDK带有的随机数方法还是程序员自己编写的随机数方法,都是通过一个或简单或复杂的算法生成的。因此都是伪随机数,都具有不安全性。因此从这个意义,随机数可以分为一般随机数,逼真随机数和真实随机数。理论上计算机编程是不可能实现真实随机数的。我们能做的只有尽可能的逼真。

例如,使用每次生成随机数,使用系统时间作为seed,就可以相对简单地构建一个不易破解的随机数生成器。

public static int closeRand(int totalNum){
        int random;
        Random randomGenerator=new Random(System.nanoTime());
        random=randomGenerator.nextInt(totalNum);
        return random;
    }

再比如JDK还提供了java.security.SecurityRandom类,它继承了java.util.Random类但重写了生成方法,可以产生强随机数:

    static int secureRand(int n) {  
       final int offset = 123456;  // offset为固定值,避免被猜到种子来源(和密码学中的加salt有点类似)  
       long seed = System.currentTimeMillis() + offset;  
       SecureRandom sr;  
       try {  
           sr = SecureRandom.getInstance("SHA1PRNG");  
           sr.setSeed(seed);  
           return sr.nextInt();  
       } catch (NoSuchAlgorithmException e) {  
           e.printStackTrace();  
       }   
       return 0;  
    }

毫无疑问,在降低效率的代价下提升了安全性。

参考资料:
http://www.cnblogs.com/greatfish/p/5845924.html
http://www.iteye.com/topic/872860
http://blog.csdn.net/ultrani/article/details/7818082

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值