从源码角度分析UUID的实现原理

本文详细探讨了Java中的UUID类,从类定义、成员变量、构造函数到各种生成UUID的方法,包括randomUUID()、nameUUIDFromBytes()和fromString()。通过源码分析,揭示了UUID字符串的构成和生成过程,以及不同方法在生成UUID时的差异。此外,还介绍了UUID实例方法,如获取版本信息、时间戳和变体编号。测试验证部分展示了不同方式创建UUID实例的结果和限制。

这是《水煮 JDK 源码》系列 的第 11 篇文章,计划撰写100篇关于JDK源码相关的文章

UUID 的全称是 universally unique identifier,表示通用唯一标识符,UUID 类位于 java.util 包下,自 JDK 1.5 版本新增的,它是一个 final 类,不能被继承,在平常的开发中,通常会使用 UUID 类来生成唯一的标识符,比如下面的代码:

public static void main(String[] args) {
   
   
    System.out.println(UUID.randomUUID());
}

运行后,输出的结果如下:

981cd0fb-91cf-4d55-ba60-377806e6051a

上面的结果中显示的就是默认的 UUID 字符串,它是由数字、字母和 - 组成,其中数字和字母共占32个字符,- 占4个字符,总共36个字符,当我们运行上面的程序时,实际上会调用 UUID 哪些方法呢?具体如下:

UUID.randomUUID() > new UUID() > toString()

那么 UUID 是如何生成的呢?32个字符又分别代表什么含义呢?下面通过具体的源码来了解一下。

1、UUID 类定义

UUID 类实现了 SerializableComparable 接口,其定义如下:

public final class UUID implements java.io.Serializable, Comparable<UUID> {
   
   
	...
}
  • Serializable :它是一个标记接口,没有任何方法定义,用于对象的序列化;
  • Comparable :该接口只有一个 compareTo 方法,通常用于对实现它的类的对象进行比较大小;

2、成员变量

UUID 类中定义了2个成员变量,分别代表最高有效64位和最低有效64位,如下:

/** 最高有效64位 */
private final long mostSigBits;

/** 最低有效64位 */
private final long leastSigBits;

mostSigBitsleastSigBits 它们是构成 UUID 标识符的重要组成部分。

3、构造函数

UUID 类提供了 2 个构造函数,其定义如下:

/** 私有的构造方法 */
private UUID(byte[] data) {
   
   
    long msb = 0;
    long lsb = 0;
    // 通过 assert 断言来判定参数 data 长度是否为 16
    assert data.length == 16 : "data must be 16 bytes in length";
    for (int i=0; i<8; i++)
        msb = (msb << 8) | (data[i] & 0xff);
    for (int i=8; i<16; i++)
        lsb = (lsb << 8) | (data[i] & 0xff);
    this.mostSigBits = msb;
    this.leastSigBits = lsb;
}

public UUID(long mostSigBits, long leastSigBits) {
   
   
    this.mostSigBits = mostSigBits;
    this.leastSigBits = leastSigBits;
}

在构造函数中,主要是给成员变量 mostSigBitsleastSigBits 赋值,虽然 UUID 提供了 public 构造函数,但是在平时开发中,可能很少直接通过构造函数来创建 UUID 对象,更多的是使用 randomUUID() 方法,下面通过断点方式来看一下这个私有构造函数计算出的 mostSigBitsleastSigBits 具体值是多少,如下:

::: hljs-center

image20220809150530214.png

:::

4、方法

UUID 类中的方法主要分为静态方法和实例方法,其中静态方法主要用于创建 UUID 实例的,而实例方法主要用于获取 UUID 中的一些基本信息,比如版本号、时间戳、时钟序列等。

4.1 静态方法 - randomUUID()
public static UUID randomUUID() {
   
   
    // 通过内部静态类 Holder 获取 SecureRandom 对象
    SecureRandom ng = Holder.numberGenerator;
	// 定义一个长度为 16 的字节数组
    byte[] randomBytes = new byte[16];
    // 通过 SecureRandom.nextBytes() 方法随机生成 16 个字节数字,并填充至数组中
    ng.nextBytes(randomBytes);
    // 索引为 6 的字节数表示的是 UUID 的版本号
    // 首先清除版本号,然后再设置版本号为 4
    randomBytes[6]  &= 0x0f;  /* clear version        */
    randomBytes[6]  |= 0x40;  /* set to version 4     */
    // 索引为 8 的字节数表示的是 UUID 的变种编号
    // 首先清除该编号,然后设置为 IETF 变种,其值 为 2
    randomBytes[8]  &= 0x3f
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值