Java中关于随机数的基本应用

前言

随机数【随机数是指:广义的随机数包括随机字符串等】在编程中用很广泛的应用的,最为常见的有:模拟用户随机算法、数据库中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)

二、生成指定大小范围的随机数

指定大小范围的随机数很显然是属于:前后两次生成的随机数可以相同[仅仅是在本次操作中有效]类型。

1.常用的基本公式

生成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);
    }
2.两种方式的比对:

两种方法都可以生成指定大小范围随机数,区别在于:
1.Math.random()生成随机数不需要new对象对内存占用较小,但是相对耗时;
2.new Random().nextInt(int bound) 生成随机数new出对象 Random()然后生成随机数,相对吃内存,但是时间确只有Math.random()的一半左右;
有点类似是方式1是:时间换空间,方式 2是:空间换时间;

三、Random伪随机数的问题

代码说话:

 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))所以结果都是一个结果。

四、UUID类型的随机数

这一类属于典型的:每次生成是随机数不能相同[作为永久的唯一标识符存储];例如:数据库的主键,有些设备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进行转换。
1.Java中生成随机UUID的方法

Java中实现方式是借助JDK中提供的UUID类,获取随机数;

  public static String getUUID(){
        return UUID.randomUUID().toString().replace("-","");
    }
2.应用示例

个人在工作曾经遇到的问题是:设备的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;

欢迎诸位批评指正;

由于个人本身就是半路出家的开发,计算机和编程基础知识浅薄,而且目前工作经验相对欠缺,所以文中难免有纰漏错误之处,望诸位同行朋友海涵不吝赐教,本人不胜感激;

你可能感兴趣的:(Java中关于随机数的基本应用)