Java随机数

来源:互联网 发布:数据库题库和答案2016 编辑:程序博客网 时间:2024/06/05 14:13

为什么说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));

结果:

5140-----------------5050

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
原创粉丝点击