标签:
一个小问题引发的思考
随机生成20个不重复A-Z的字符串,并且顺序排列
题目挺简单要注意几个点,一 :A-Z的生成 二 : 随机数 三 :不重复, 顺序排列
A-Z的生成:利用ascii码表生成字母 //确定A-Z的 ascii码表 (65-90)
i=65
char c=(char) i;//c即为"A"
再利用随机数生成 不同的字符串
int i=new Random().nextInt(26)+65;
20个不重复的,循环确定个数,set保存不重复的对象集合
while(true){ int i=new Random().nextInt(26)+65; char c=(char) i; if(set.size()<=20){ set.add(c); } else{ break; } }
最后一步:顺序保存,只需要set集合使用treeSet就可,treeSet是根据对象实现comparable接口按顺序保存对象。
完整例子
public static void main(String[] args) { //确定A-Z的 ascii码表 (65-90) TreeSet<Character> set =new TreeSet<Character>(); while(true){ int i=new Random().nextInt(26)+65; char c=(char) i; if(set.size()<=20){ set.add(c); } else{ break; } } for(Iterator<Character> i=set.iterator();i.hasNext();){ char c= i.next(); System.out.println(c); } }
上述只是一个很简单的小问题,但有两个问题可以深入探讨下
一:随机数
java生成的随机数是伪随机数,即不是真正的随机,只是按照一定的规则模拟出来的。
java中生成随机数有两种方法 一种就是开始上面实现的随机数 int i=new Random().nextInt(26) 生成一个0-25的实际整数
另一种则是 Math.random() 生成一个0-1的浮点数
这两种的区别
先看 Math.random() 的源码
private static Random randomNumberGenerator; private static synchronized Random initRNG() { Random rnd = randomNumberGenerator; return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd; } public static double random() { Random rnd = randomNumberGenerator; if (rnd == null) rnd = initRNG(); return rnd.nextDouble(); }
简单的说,Math.random() 还是调用了 random对象的 nextDouble()方法,只不过random对象是静态的,单一的,上锁的random对象
接下来看 nextDouble()方法,nextDouble()调用了next()方法,值得说下的是,nextInt()方法之调用了一次next(),速度会比nextDouble()快一丢丢
public double nextDouble() { return (((long)(next(26)) << 27) + next(27)) / (double)(1L << 53); }
接下来继续看next()方法, next()中有一个很重要的属性 oldseed,所有运算结果都是根据它生成,而oldseed是怎么生成的
protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed)); return (int)(nextseed >>> (48 - bits)); }
又下面可以知道.oldseed是由几个常数 加系统时间来运算确定的 ,所以呢java随机数不是真随机只是个伪随机,并且不是很安全,因为很容易被算是随机值,但是可以用java.security.SecureRandom,这个更安全,因为重写了next()方法。
public Random() { this(seedUniquifier() ^ System.nanoTime()); } private static long seedUniquifier() { // L‘Ecuyer, "Tables of Linear Congruential Generators of // Different Sizes and Good Lattice Structure", 1999 for (;;) { long current = seedUniquifier.get(); long next = current * 181783497276652981L; if (seedUniquifier.compareAndSet(current, next)) return next; } } private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
最后:http://blog.csdn.net/ultrani/article/details/7818082 这边博文的作者写的更清晰,也更深入的说明random函数算法的原理,有兴趣可以去看下
标签:
原文地址:http://www.cnblogs.com/qiuyuedong/p/4699767.html