java 8 uuid_jdk源码分析(八)——UUID

e4e8b48d9c71

一.基础概念

UUID:Universally Unique Identifier,通用唯一识别码。是一种软件建构的标准,亦为开放软件基金会组织在分布式计算环境领域的一部分。UUID的目的,是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。

历史

UUID最初被应用在Apollo Network Computing System,随后被开放软件基金会(OSF)应用在分布式计算环境领域。

后来,IETF(国际互联网工程任务组)将UUID作为一种标准发布在RFC 4122。

格式

标准的UUID格式如下:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

除连字符-外,上面每个字符都是一个十六进制的数字,共有5个部分组成,第一部分8个,第二部分4个,第三部分4个,第四部分4个,第五部分12个,8-4-4-4-12,一共32个十六进制字符,因此一共是128位。

其中,M表示UUID的版本,N表示UUID的变体。

变体

为了能兼容过去的UUID,以及应对未来的变化,因此有了变体(Variants)这一概念。目前已知的变体有如下几种:

variant 0:N的格式为0xxx。为了向后兼容预留。

variant 1:10xx。当前正在使用的。

variant 2:11xx。为早期微软GUID预留。

variant 3:111x。为将来扩展预留。目前暂未使用。

因此,可以认为,目前正在使用的UUID都是variant1,取值是8,9,a,b中的一个。

版本

版本用于定义UUID的形成方法:

Version 1:基于时间和MAC地址。由于使用了MAC地址,因此能够确保唯一性,但是同时也暴露了MAC地址,私密性不够好。

Version 2:DCE安全的UUID。该版本在规范中并没有仔细说明,因此并没有具体的实现。

Version 3 :基于名字空间(MD5)。用户指定一个名字空间和一个字符串,通过MD5散列,生成UUID。字符串本身需要是唯一的。

Version 4 :基于随机数。虽然是基于随机数,但是重复的可能性可以忽略不计,因此该版本也是被经常使用的版本。

Version 5 : 基于名字空间(SHA1)。跟Version 3类似,但是散列函数编程了SHA1。

二.类定义

java sdk中提供了UUID的Version 3和Version 4的具体实现。我们来看一下具体的类定义:

public final class UUID

implements java.io.Serializable, Comparable

该类被定义为final的,说明不希望被继承。

类中定义了如下变量:

// 高64位

private final long mostSigBits;

// 低64位

private final long leastSigBits;

// 版本

private transient int version = -1;

// 变体

private transient int variant = -1;

// 时间戳,版本1专用

private transient volatile long timestamp = -1;

// 时钟频率,版本1专用

private transient int sequence = -1;

// mac地址,版本1专用

private transient long node = -1;

// hash值

private transient int hashCode = -1;

UUID是128位的,在Java的UUID中,是将这128分为高64位和低64位分别存储的。

三.核心方法

1.构造方法

共有两个构造方法:

// 通过字节数组来生成UUID,字节数组长度必须是16个字节

private UUID(byte[] data) {

long msb = 0;

long lsb = 0;

assert data.length == 16;

// 将前8个字节赋值到高64位

for (int i=0; i<8; i++)

msb = (msb << 8) | (data[i] & 0xff);

// 将后8个字节赋值到低64位

for (int i=8; i<16; i++)

lsb = (lsb << 8) | (data[i] & 0xff);

this.mostSigBits = msb;

this.leastSigBits = lsb;

}

// 直接指定高64位和低64位的值

public UUID(long mostSigBits, long leastSigBits) {

this.mostSigBits = mostSigBits;

this.leastSigBits = leastSigBits;

}

2.randomUUID

该方法可以生成一个版本4的UUID。

// 生成版本4UUID

public static UUID randomUUID() {

// 伪随机数生成器

SecureRandom ng = Holder.numberGenerator;

byte[] randomBytes = new byte[16];

// 生成16个字节共128位的伪随机数

ng.nextBytes(randomBytes);

// 将带有版本号的那个字节与00001111进行按位与,表示版本号的4个bit将变成0000

randomBytes[6] &= 0x0f;

// 将带有版本号的字节与01000000进行按位或,表示版本号的4个bit将变成0100,说明是版本4

randomBytes[6] |= 0x40;

// 将带有变体的字节与00111111进行按位与,表示变体的4个bit将变成00xx

randomBytes[8] &= 0x3f; /* clear variant */

// 将带有变体的字节与10000000进行按位或,表示变体的4个bit将变成10xx,说明是变体2

randomBytes[8] |= 0x80; /* set to IETF variant */

return new UUID(randomBytes);

}

3.nameUUIDFromBytes

该方法将生成一个版本3的UUID。

public static UUID nameUUIDFromBytes(byte[] name) {

// MessageDigest是信息摘要类,提供md5,sha1等算法。

MessageDigest md;

try {

// 获取提供MD5算法的MessageDigest实例

md = MessageDigest.getInstance("MD5");

} catch (NoSuchAlgorithmException nsae) {

throw new InternalError("MD5 not supported");

}

// 利用md5算法对结合name,生成md5值,md5和UUID都是16个字节

byte[] md5Bytes = md.digest(name);

// 以下操作类似于randomUUID,只是会将版本复制为3

md5Bytes[6] &= 0x0f;

md5Bytes[6] |= 0x30;

md5Bytes[8] &= 0x3f;

md5Bytes[8] |= 0x80;

return new UUID(md5Bytes);

}

参考资料:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值