随机数【随机数是指:广义的随机数包括随机字符串等】在编程中用很广泛的应用的,最为常见的有:模拟用户随机算法、数据库中ID、临时文件名、随机端口号、甚至可以作为设备ID等等诸多用处。
随机数的应用中可以分为两种类型:
- 1.每次生成是随机数不能相同[作为永久的唯一标识符存储];
- 2.前后两次生成的随机数可以相同[仅仅是在本次操作中有效];
常见的生成随机数方法
- 1.通过System.currentTimeMillis()获取当前时间毫秒数的long型数字;
- 2.通过Math.random()方法返回一个0到1之间的double随机数;
- 3.通过Random类来产生一个随机数;
- 4.通过UUID.randomUUID().toString()获取一个随机字符串;
- 5.通过Mac地址等设备硬件唯一标识和其他组合生成随机数;
题目:Math.Round(11.5);和Math.Round(-11.5);返回值是多少?
结果是:12,-11;
这个是基础是面试题当然结果还有点小扰人,还需要小心下;顺便回顾一下Java中
Math.ceil(double a)、Math.floor(double a) 、 Math.rint(double a) 中的取整API,直接看代码:
/**
* 向上取整,即大于这个数的最小的那个整数
* @param a 取整数字
* @return 取整结果
*/
public static double ceil(double a) {
return StrictMath.ceil(a); // default impl. delegates to StrictMath
}
/**
* 向下取整,即小于这个数的最大的那个整数;
* @param a 取整数字
* @return 取整结果
*/
public static double floor(double a) {
return StrictMath.floor(a); // default impl. delegates to StrictMath
}
/**
* 返回最接近该值的那个整数。注意如果存在两个这样的整数,则返回其中的偶数;
* @param a 取整数字
* @return 取整结果
*/
public static double rint(double a) {
return StrictMath.rint(a); // default impl. delegates to StrictMath
}
/**
*“四舍五入”,但当参数为负数时不太好理解,直接上源码应该比较好理解。
* Math.round(x) = Math.floor(x + 0.5)
* @param a 取整数字
* @return 取整结果
*/
public static long round(double a)
//JDK中两个只是参数和返回类型不同而已
public static int round(float a)
指定大小范围的随机数很显然是属于:前后两次生成的随机数可以相同[仅仅是在本次操作中有效]类型。
生成int随机数
生成随机数方式1:Math.random()
公式: int sends = (int) (MIN + Math.random() * (MAX - MIN + 1));
生成随机数方式2 : Random().nextInt(int bound)
公式: int randNumber =rand.nextInt(MAX - MIN + 1) + MIN;
生成英文字母随机数
生成随机英文字母方式1: 借助Math.random()
公式:char c= (char)(‘a’+Math.random()*(‘z’-‘a’+1));
生成随机英文字母方式2 :借助Random().nextInt(int bound)
公式:char c= (char)(rand.nextInt(‘z’-‘a’+1) + ‘a’);
/**
* Random 获取随机数
*
* @param Min 最小值
* @param Max 最大值
* @return 随机数
*/
public static int getIntRandom(int Min ,int Max){
Random rand = new Random();
return rand.nextInt(Max-Min+1)+Min;
}
/**
* Math 获取随机数
*
* @param Min 最小值
* @param Max 最大值
* @return 随机数
*/
public static int getIntRandom(int Min, int Max) {
return (int) (Min + Math.random() * (Max - Min + 1));
}
/**
* Math 获取随机英文字母小写
*
* @param Min 最小值
* @param Max 最大值
* @return 随机数
*/
public static char getCharRandom(char Min, char Max) {
return (char) (Min + Math.random() * (Max - Min + 1));
}
/**
* Random 获取随机英文字母小写
*
* @param Min 最小值
* @param Max 最大值
* @return 随机数
*/
public static char getCharRandom(char Min, char Max) {
Random rand = new Random();
return (char) (rand.nextInt(Max - Min + 1) + Min);
}
两种方法都可以生成指定大小范围随机数,区别在于:
1.Math.random()生成随机数不需要new对象对内存占用较小,但是相对耗时;
2.new Random().nextInt(int bound) 生成随机数new出对象 Random()然后生成随机数,相对吃内存,但是时间确只有Math.random()的一半左右;
有点类似是方式1是:时间换空间,方式 2是:空间换时间;
代码说话:
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(creatRandom(1000));
}
}
/**
*生成随机数
*/
public static long creatRandom(int seeds) {
return new Random(1000).nextInt();
}
结果:
-1244746321
-1244746321
-1244746321
-1244746321
-1244746321
-1244746321
-1244746321
-1244746321
-1244746321
-1244746321
正确的代码:
private static Random random;
public static long creatRandom() {
if (random == null) {
random = new Random(2000);
}
return random.nextInt();
}
问题的根本原因是:JavaJDK中的随机数是一个伪随机数:
【Random类的实例用于生成伪随机数流。此类使用 48 位的种子,使用线性同余公式对其进行修改(请参阅 Donald Knuth 的《The Art of Computer Programming, Volume 2》,第 3.2.1 节)】
在原码中是一个固定的算法线性算法,所以每次都new出Random 对象ji即每次都是一个初始化的AtomicLong 的 seed,再同过一个固定的算法(protected int next(int bits))所以结果都是一个结果。
这一类属于典型的:每次生成是随机数不能相同[作为永久的唯一标识符存储];例如:数据库的主键,有些设备MAC地址是随机的也可以用来作为设备的唯一标识等。
什么是UUID
UUID含义是通用唯一识别码 (Universally Unique Identifier),这是一个软件建构的标准,也是被开源软件基金会 (Open Software Foundation, OSF) 的组织应用在分布式计算环境 (Distributed Computing Environment, DCE) 领域的重要部分
UUID的组成:
- 1.当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。
- 2.时钟序列。
- 3.全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。
UUID标准
- 微软的GUID标准[使用最普遍]。UUID格式为:xxxxxxxx-xxxx- xxxx-xxxxxxxxxxxxxxxx(8-4-4-16),其中每个 x 是 0-9 或 a-f 范围内的一个十六进制的数字。
- 标准的UUID[Java中使用标准]。格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12),可以从cflib 下载CreateGUID() UDF进行转换。
Java中实现方式是借助JDK中提供的UUID类,获取随机数;
public static String getUUID(){
return UUID.randomUUID().toString().replace("-","");
}
个人在工作曾经遇到的问题是:设备的Mac地址随机的,所以不能使用mac地址作为设备的唯一的标识,所以只好采用的UUID作为唯一的标识,即当用户登录时候立即生成一个UUID并且随着应用一同存储,在服务端就用这个UUID作为设备标识,用于实现其他需求;
示例代码:
public static String devID = null;
private static final String DEVICE_UUID = "DEVICE_UUID";
/**
* 设备登录上线时需要携带 DeviceId
* @param pathUUID DeviceId 存储文件路径
* @return DeviceId
*/
public synchronized static String getDevId(String pathUUID) {
if (devID == null) {
File device = new File(pathUUID, DEVICE_UUID);
try {
if (!device.exists())//deviceID是否已经存在
writeRFile(device);//没有先存储
devID = readRFile(device);//存在,则直接读取,不再生成,确保deviceID不发生修改
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return devID;
}
private static String readRFile(File devID) throws IOException {
RandomAccessFile f = new RandomAccessFile(devID, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeRFile(File devID) throws IOException {
FileOutputStream out = new FileOutputStream(devID,false);
String id =getUUID();
out.write(id.getBytes());
out.close();
}
public static String getUUID(){
return UUID.randomUUID().toString();
}
当然了在网上最多见的借助时间戳和UUID一起生成数据库中的ID;
由于个人本身就是半路出家的开发,计算机和编程基础知识浅薄,而且目前工作经验相对欠缺,所以文中难免有纰漏错误之处,望诸位同行朋友海涵不吝赐教,本人不胜感激;