您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

了解UUID在JDK的底层实现 [源码分享]

  • 时间:2022-07-08 02:11 编辑: 来源: 阅读:307
  • 扫一扫,手机访问
摘要:了解UUID在JDK的底层实现 [源码分享]
前提UUID是通用唯一标识符的缩写,翻译成通用唯一标识符或全局唯一标识符。 关于UUID的描述,下面是从规范文件A universal Unique Identifier(UUID)URN namespace的摘录:UUID(也叫GUID)定义了统一资源名命名空间。 UUID的长度为128比特,可以保证在空间和时间上的唯一性。 动机:“使用UUID的一个主要原因是不需要集中管理。其中一种格式定义了IEEE 802节点标识符,而其他格式没有。 UUID可以按需自动生成,并应用于多个不同的场景。 UUID算法支持极高的分配率,每台机器每秒可以生成超过1000万个uuID,因此可以作为事务id使用。 UUID的大小固定为128位。与其他替代方案相比,它具有体积小的优点,非常适合在数据库中进行排序、哈希和存储,并且易于编程。 这里只需要牢记UUID的几个核心特殊性:全局时空唯一性固定长度为128位,即16字节(1字节= 8位)的分配率极高,单机每秒可生成1000多万个uuid(实际更高)。这里,详细分析了JDK的UUID生成算法。 在写这篇文章的时候,JDK是JDK11。 我们先来谈谈UUID。为了写一个简单的总结,只粗略摘录了规范文档中的几个章节。在这里,我们来详细谈谈UUID、碰撞概率等几个定义。 UUID定义UUID是软件构造的标准,是分布式计算环境领域开放软件基础的一部分。 本标准的目的是使分布式系统中的所有元素或组件都具有唯一的可识别信息。由于极低的冲突频率和高效的算法,它不需要对唯一可识别信息的生成进行集中控制和管理。因此,每个用户可以自由地创建不与他人冲突的UUID。 “UUID本质上是一个128位的数”,这是一个巨大的位长。理论上,UUIDs的总数是2 128。 这个数字可以这样估算:如果“每纳秒”产生“1万亿”个不同的uuid,那么要用100多亿年才能用完所有的uuid。 UUID的变体和版本在定义UUID标准和算法时,提供了许多变体和版本来考虑历史兼容性和未来扩展。 以下变体和版本是从维基百科的版本章节和RFC 4122的变体章节中描述的。 目前已知的变种有:变种0xx:保留,NCS向后兼容,变种10x:IETF aka leach-salt变种(本类使用),通称leach–salzUUID或IETF UUID,JDK目前使用的UUID变种110:保留,微软公司向后兼容,微软GUID早期保留变种variant 111:保留用于将来定义,将来扩展保留。目前已知的尚未使用的变种版本如下:空UUID(特殊版本0),用0000000-0000-0000-0000-0000-00000000表示,即所有位都是0日期时间和MAC地址(版本1):基于时间和MAC地址的版本,通过计算当前时间戳、随机数和机器MAC地址得到。 因为MAC地址,这可以保证它在世界上的唯一性。 但是,如果使用MAC地址,就会出现MAC地址暴露问题。 在局域网的情况下,可以使用IP地址来代替日期-时间和MAC地址,DCE安全版本(版本2):用于分布式计算环境安全的UUID。算法与版本1基本相同,但时间戳的前四位将改为POSIX UID或GIDnamespace基于名称的MD5(版本3):可以通过计算名称和名称空间的MD5哈希值获得。 这个版本的UUID保证了同一名称空间中不同名称生成的uuid的唯一性;UUID在不同命名空间中的唯一性;在同一个命名空间中重复生成同名的uuid是一样的随机(版本4):uuid是根据随机数或者伪随机数生成的。 可以计算该UUID的复制概率。另一个特点是保留了6位来存储变体和版本属性,所以有122个随机生成的位,总量为2 ^ 122,小于其他变体的总量:基于命名空间名称的SHA-1(版本5):与版本3类似,哈希算法改为SHA-1,JDK使用的变体是Leach-Salz,提供了基于命名空间名称的MD5(版本3)和random(版本4)两个版本的UUID代实现。 规范文档中描述了UUID的格式。UUID由16个8位数字或32个十六进制字符组成。一般的符号是8-4-4-4-12,加上连接字符——总共有36个字符。例如,# Example 123 e 4567-E89B-12 D3-A456-426614174000 # #通用格式XXXXXX-XXXXX-XXXXXXXXXXX,其中M用4位,N用1至3位分别表示版本号和变体标识。 UUID的具体布局如下:了解UUID在JDK的底层实现。根据这个表画一个图:image.png“认真注意,重复三遍”:上面提到的UUID的具体布局只适用于日期时间和MAC地址(版本1)和日期时间和MAC地址。DCE安全版(版本2),其他版本虽然采用基本相同的字段分布,但无法获取时间戳、时钟序列或用户节点ID等信息。上面提到的UUID的具体布局只适用于日期时间和MAC地址(版本1)和日期时间和MAC地址。DCE安全版(版本2),其他版本虽然采用基本相同的字段分布,但无法获取时间戳、时钟序列或用户节点ID等信息。上面提到的UUID的具体布局只适用于日期时间和MAC地址(版本1)和日期时间和MAC地址。DCE安全版(版本2),其他版本虽然采用基本相同的字段分布,但无法获取时间戳、时钟序列或节点ID等信息。JDK只提供了版本3和版本4的实现,但是java.util.UUID的布局使用了上表中字段UUID的碰撞概率来计算UUID的总量。虽然巨大,但如果持续使用,假设每纳秒产生超过1万亿个uuid,并且人类足够幸运能够在100亿年后繁殖,那么uuid的总量将是。 那么,如何计算UUID的碰撞概率呢?这是一个数学问题,可以用著名的“生日悖论”来处理:用一万个字符理解UUID在JDK的底层实现。上图来自某搜索引擎百科。 正好维基百科给出了碰撞概率的计算过程,其实就是生日悖论的计算方法。这里有个帖子:image.png对碰撞概率的计算是基于Leach-Salz变体和版本4,结论是在103万亿UUIDs中找到重复项的概率是十亿分之一。要生成冲突率为50%的UUID,至少需要生成2.71 * 1 _ 000 _ 000 3个uuid。 image.pngUUID的使用场景基本上所有需要使用全局唯一标识符的场景都可以使用UUID,除非对长度有明确的限制。常用的场景有:日志帧映射诊断上下文中的TRACE_IDAPM工具或OpenTracing规范中的SPAN_ID,特殊场景下的数据库主键或虚拟外键事务ID (order ID)等......................................................................... 上面提到的JDK的变种是Leach-Salz(变种2),它提供了基于名称空间名称的MD5(版本3)和random(版本4)两个版本的UUID代实现。实际上,java.util.UUID提供了四种生成UUID实例的方法:最常用的方法是调用静态方法UUID#randomUUID(),这是4版的静态工厂方法,然后调用静态方法UUID # nameidfrombytes(byte[]name)。这是版本3的静态工厂方法。此外,它从STRING(STRING name)调用静态方法UUID #,这是一个静态工厂方法,解析8-4-4-4-12格式字符串以生成UUID实例。还有一个低级构造函数UUID (long most sigbits,long least sigbits)。对于这个用户,最常用的方法是实例方法toString(),它将UUID转换为由十六进制字符串拼接而成的8-4-4-4-12形式,例如:字符串UUID = UUID。随机UUID()。tostring();其他Getter方法:UUID uuid = uuid . randomuuid();//返回版本号int version = uuid . version();//返回变量编号int variant = uuid . variant();//返回时间戳——这个方法会报错。只有基于时间的UUID,即版本1或版本2的UUID实现,才能返回时间戳long timestamp = uuid . timestamp();//返回时钟序列——这个方法会报错。只有基于时间的UUID,即版本1或版本2的UUID实现,才能返回时钟序列long clock sequence = uuid . clock sequence();//返回节点ID——这个方法会报错。只有基于时间的UUID,即版本1或版本2的UUID实现,才能返回节点IDlong nodeId = uuid . node();可以验证不同静态工厂方法的版本和变体号:UUID uuid = uuid . random uuid();int version = uuid . version();int variant = uuid . variant();system . out . println(string . format("版本:%d,变体:%d ",版本,变体));uuid = uuid . namuuidfrombytes(new byte[0]);version = uuid . version();variant = uuid.variant()。system . out . println(string . format("版本:%d,变体:%d ",版本,变体));//输出结果版本:4,变体:2版本:3,变体:2探索UUID源代码在JDK的实现。java.util.UUID由final修饰,实现可序列化和可比较的接口。一般来说,它有以下具体特征:不可变,一般来说,工具类是这样定义的。可以序列化和反序列化的不同对象可以进行比较,方法将在比较后进行分析。下面将从不同方面分析java.util.UUID的源代码实现:属性和构造函数随机数版本实现命名空间基于名称的MD5版本实现和其他实现打印格式比较相关方法属性和构造函数。如前所述,在JDK只提供版本3和版本4的实现。但是java.util.UUID的布局采用了UUID规范中的字段定义,总长度为128位,刚好可以存放在两个长类型的整数中,所以我们看到UUID类中有两个长类型的整数值:public final类UUID实现java.io.serializable,comparable < UUID & gt;{//暂时省略其余代码/* *该UUID的最高有效64位。* UUID中有效的高64位* * @ serial */Private最终最长Sigbits/* *该UUID的最低64位。* UUID的有效低64位* * @ serial */private final long last sigbits;//其余代码暂且省略}从UUID类的注释中可以看到具体的字段布局如下:《上位64位mostSigBits的布局》一万字了解UUID在JDK的底层实现《下位64位leastSigBits的布局》一万字了解UUID在JDK的底层实现。然后再看UUID的其他成员属性和构造函数:public final class UUID实现java.io.serializable,comparable < UUID & gt;{//暂时省略剩下的代码// Java语言访问类,里面存储了很多底层相关的访问或者转换方法。在UUID主要使用toString()实例方法将其格式化为8-4-4-4-12的形式,并委托给Long.fastUUID()方法private static Final JavaLangAccess JLA = shared secrets . getjavalangaccess();//静态内部类保证SecureRandom初始化,用于版本4的随机数UUID版本生成安全随机数私有静态类Holder { Static final SecureRandom number generator = new SecureRandom();}//通过长度为16 { longmsb = 0;的字节数组计算mostSigBits和leastSigBits的值,初始化UUID实例private uuid(byte[]data);长LSB = 0;assert data.length == 16:“数据长度必须为16个字节”;for(int I = 0;我& lt8;i++)msb =(msb & lt;& lt8)|(data[I]& amp;0x ff);for(int I = 8;我& lt16;i++)LSB =(LSB & lt;& lt8)|(data[I]& amp;0x ff);this.mostSigBits = msbthis.leastSigBits = lsb}//直接指定mostSigBits和leastSigBits构造UUID实例公共uuid (long mostsigbits,long least sigbits){ this . mostSigBits = mostSigBits;this . least sigbits = least sigbits;}//其余代码暂时省略}私有构造私有UUID(byte[] data)中有几个位操作技巧:long msb = 0;长LSB = 0;assert data.length == 16:“数据长度必须为16个字节”;for(int I = 0;我& lt8;i++)msb =(msb & lt;& lt8)|(data[I]& amp;0x ff);for(int I = 8;我& lt16;i++)LSB =(LSB & lt;& lt8)|(data[I]& amp;0x ff);this.mostSigBits = msbthis.leastSigBits = lsb输入字节数组的长度为16,mostSigBits由字节数组的前8个字节转换而来,leastSigBits由字节数组的后8个字节转换而来。 从中间变量msb或lsb中提取字节位进行计算时:先左移8位,保证要计算的位为0,然后将计算的位左移,再将右边要提取的字节数据[i]的8位与0xff(补码1111111)进行或运算,保证8位以下的高位补码为0, 并且超过8位的高位会被截断到低位8位,即data[i] & 0xff保证得到的补码是8位前两步的结果,然后进行或计算一个模拟过程如下:(为了明显区分,我每4位加下划线)(简答只看字节数组的前4个字节,只看long类型的前4个字节)0x ff = = 111 _ 1111 Long MSB = 0 = >; 000 _ 0000 0000 _ 0000 0000 _ 0000 0000 _ 0000 byte[]data 0000 _ 0001 0000 _ 0010 0000 _ 0100 0000 _ 1000 I = 0(第一轮)MSB < & lt8 = 0000 _ 0000 0000 _ 0000 0000 _ 0000 0000 _ 0000 data[I]& amp;0xff = 0000_0001。1111 _ 1111 = 0000 _ 0001(msb & lt;& lt8)|(data[I]& amp;0x)= 0000 _ 0000 0000 _ 0000 0000 _ 0000 0000 _ 0001(第一轮MSB = 0000 _ 0000 0000 _ 0000 0000 _ 0001)I = 1(第二轮MSB)< & lt;8 = 0000 _ 0000 0000 _ 0000 0000 _ 0001 0000 _ 0000 data[I]& amp;0xff = 0000 _ 0010 & amp1111 _ 1111 = 0000 _ 0010(msb & lt;& lt8)|(data[I]& amp;0x)= 0000 _ 0000 0000 _ 0000 0000 _ 0001 0000 _ 0010(第二轮MSB = 0000 _ 0000 0000 _ 0001 0000 _ 0010)I = 2(第三轮)MSB < & lt8 = 0000 _ 0000 0000 _ 0001 0000 _ 0010 0000 _ 0000 data[I]& amp;0xff = 0000 _ 0100 & amp1111 _ 1111 = 0000 _ 0100(msb & lt;& lt8)|(data[I]& amp;0x)= 0000 _ 0000 0000 _ 0001 0000 _ 0010 0000 _ 0100(第三轮MSB = 0000 _ 0000 _ 0001 0000 _ 0010 0000 _ 0100)I = 3(第四轮)MSB < & lt8 = 0000 _ 0001 0000 _ 0010 0000 _ 0100 0000000 data[I]& amp;0xff = 0000 _ 1000 & amp1111 _ 1111 = 0000 _ 1000(msb & lt;& lt8)|(data[I]& amp;0x)= 0000 _ 0001 0000 _ 0010 0000 _ 0100 0000 _ 1000(第四轮MSB = 0000 _ 0001 0000 _ 0010 0000 _ 0100 0000 _ 1000)等等。私有构造函数执行后,其长度为 在对版本实现构造函数进行分析后,重点分析了重静态工厂方法UUID#randomUUID(),这是最常用的方法:公共静态UUID Random uuid(){//静态内部类Holder持有的SecureRandom的实例,以保证预先初始化Secure Random NG = Holder . number generator;//生成一个16字节的安全随机数,放入一个长度为16字节的字节数组[]random bytes = new byte[16];ng . nextbytes(random bytes);//将版本号所在的位清零,复位为4个随机字节[6]& = 0x0f;/*清除版本*/random bytes[6]| = 0x 40;/*设置为version 4 *//将变量号所在的位清零,复位为random bytes[8]& = 0x3f;/* clear variant */random bytes[8]| = 0x 80;/*设置为IETF variant */ return新UUID(random bytes);}关于上面的位操作,这里可以用一个极端的例子进行推导:假设randomBytes[6] = 1111_1111//清除版本位随机字节[6]& = 0x0f = & gt;1111 _ 1111 & amp000 _ 111 = 0000 _ 1111获取randomBytes[6] = 0000_1111(此处高4位清零)//将版本位设置为整数4 = >:十六进制0x40 = >:二进制补码0100 _ 0000随机字节[6]| = 0x 40 = >:000 _ 111 | 0100 _ 0000 = 0100 _ 1111获取randomBytes[6]对应十进制数4,同样,假设randomBytes[8] = 1111_1111//清零变量位随机字节[8]& = 0x3f = & gt;1111 _ 1111 & amp011 _ 1111 = 0011 _ 1111//将variant位设置为整数128 = >:十六进制0x80 = >:二进制补码1000_0000(此处取左上2位)随机字节[8]| = 0x 80 = >:011 _ 1111 | 1000 _ 0000 = 1011 _ 1111结果:variant bit = >: 10(2位)= >对应于十进制数2。UUID的Getter方法,比如version()和variant(),其实就是找到对应的位,转换成十进制整数返回。如果你是位操作熟练的话,应该很容易理解,这类Getter方法后面就不分析了。 “随机数版本的实现强烈依赖于SecureRandom生成的随机数(字节数组)” SecureRandom的引擎提供者可以从sun . security . provider . sun entries查看,不同系统版本的JDK实现会选择不同的引擎,比如NativePRNG。 JDK11配置文件$ Java _ home/conf/security/Java . security中的securerandom.source属性用于指定系统默认的随机来源:image.png,这里有个小知识点。要得到密码学意义上的安全随机数,可以直接使用真随机数生成器生成的随机数,也可以使用真随机数生成器生成的随机数作为种子。 通过搜索少量资料,得知“非物理真随机数生成器”是:/dev/Linux操作系统的random facility接口和Windows操作系统的CryptGenRandom接口。如果不修改java.security的配置文件,默认的随机数提供引擎会根据不同的操作系统选择不同的实现,这里就不赘述了。 在Linux环境下,SecureRandom实例化后,并不是通过setSeed()方法将随机数设置为种子,而是使用/dev/random默认提供的安全随机数接口获取种子,生成的随机数是密码学意义上的安全随机数。 “总之,UUID私有静态内部类Holder中的SecureRandom实例可以生成安全随机数,这是JDK实现UUID版本4的重要前提” 下面总结一下随机数版本UUID的实现步骤:通过SecureRandom提供的SecureRandom number接口获取种子,生成一个16字节的随机数(字节数组)。对于生成的随机数,清除reset版本和variant对应的位,将reset版本和variant的随机数的所有位转移到mostSigBits和leastSigBits中基于命名空间名称的MD5版本的实现,然后分析版本3的实现,即基于命名空间名称的MD5版本,对应静态工厂方法UUID # nameeuidfrombytes():public静态UUID nameeuidfrombytes(byte[]name){ Message DigestMD;请尝试{ MD = message digest . getinstance(" MD5 ");} catch(nosuchalgorithm exception nsae){ throw new internal error("不支持MD5 ",nsae);} byte[]MD 5 bytes = MD . digest(name);MD5 bytes[6]& amp;= 0x0f/*清除版本*/MD 5 bytes[6]| = 0x 30;/*设置为版本3 */MD5 bytes[8]& amp;= 0x3f/* clear variant */MD 5 bytes[8]| = 0x 80;/*设置为IETF variant */返回新UUID(MD 5 bytes);}其后续基本解决方案与随机数版本基本相同(当版本位清零时,重置为3)。唯一显著的区别是,在生成原始随机数时,采用的方法是:基于输入的名称字节数组,用MD5摘要算法生成一个MD5摘要字节数组作为原始安全随机数,返回的随机数正好是16字节长。 用法很简单:uuid uuid = uuid . nameidfrombytes(" throwable ")。getbytes());基于命名空间名称的MD5版本中UUID的实现步骤如下:通过输入的命名字节数组,基于MD5算法生成一个长度为16字节的随机数。对于生成的随机数,清除重置版本和变体对应的位,将版本和变体随机数的所有位转移到mostSigBits和leastSigBits中UUID的基于命名空间名称的MD5版本,这强烈依赖于MD5算法。有一个显著的特点是,如果输入的byte[]名称相同,就会生成完全相同的UUID实例。 剩下的实现主要包括://完全自定义mostSigBits和leastSigBits,可以参照UUID标准字段布局设置,也可以根据自制的标准公共UUID(long most sigbits){ this . most sigbits = most sigbits;this . least sigbits = least sigbits;}//基于字符串格式8-4-4-4-12的UUID输入,重新解析mostSigBits和leastSigBits。这种静态工厂方法不常用,里面的位操作就不详细探究了。来自string(string name){ int len = name . length()的公共静态UUID;if(len & gt;36){ throw new IllegalArgumentException(" UUID字符串太大");} int dash1 = name.indexOf('-',0);int dash2 = name.indexOf('-',dash 1+1);int dash3 = name.indexOf('-',dash 2+1);int dash4 = name.indexOf('-',dash 3+1);int dash5 = name.indexOf('-',dash 4+1);if(dash 4 & lt;0 | | dash5 & gt= 0){ throw new IllegalArgumentException("无效的UUID字符串:"+name);} long mostSigBits = long . parse long(name,0,dash1,16)& amp;0xffffffffLmostSigBits & lt& lt= 16;mostSigBits | = long . parse long(name,dash1 + 1,dash2,16)& amp;0xffffLmostSigBits & lt& lt= 16;mostSigBits | = long . parse long(name,dash2 + 1,dash3,16)& amp;0xffffLlong least sigbits = long . parse long(name,dash3 + 1,dash4,16)& amp;0xffffLleastSigBits & lt& lt= 48;least sigbits | = long . parse long(name,dash4 + 1,len,16)& amp;0xffffffffffffL返回新UUID(mostSigBits,leastSigBits);}打印格式打印格式如UUID#toString()方法所示,将mostSigBits和leastSigBits格式化为8-4-4-4-12的形式。下面是格式化过程的详细分析。 首先,从评论来看,格式是: UUID#toString()方法源代码如下:private static final javalangaccess jla = shared secretions . getjavalangaccess();公共字符串toString(){ return jla . fastuuid(least sigbits,mostSigBits);}↓↓公共字符串fastUUID(long lsb,long msb)//Java . lang . system private静态void setJavaLangAccess(){ shared secrets . setJavaLangAccess(){ public String fastUUID(long LSB,long msb){ return long . fastUUID(LSB,msb);} }↓↓↓↓↓Java . lang . long statistical String fast uuid(long LSB,long msb) {//compact _ strings在String类中默认为true,因此会命中if分支if (COMPACT_STRINGS) {//初始化字节数组byte[]buf = 1//LSB的低48位转换成十六进制格式写入buf-node = >: Position [24,35]格式无符号long 0 (LSB,4,buf,24,12);//LSB的高16位转换成十六进制格式写入buf-variant _ and _ sequence = >:Position[19,22]格式无符号long 0(LSB >:& gt;& gt48,4,buf,19,4);//MSB的低16位转换为十六进制格式,写入buf-time _ high _ and _ version = >:Position[14,17]格式无符号long 0 (MSB,4,BUF,14,4);//MSB中间16位转换成十六进制格式,写入buf-time _ mid = >: Position [9,12]格式无符号long 0(MSB >:& gt;& gt16,4,buf,9,4);//MSB的高32位转换成十六进制格式写入buf-time _ low = >: Position [0,7]格式无符号long 0(MSB >:& gt;& gt32,4,buf,0,8);//备用字节槽插入'-',正好占用4个字节buf[23]= '-';buf[18]= '-';buf[13]= '-';buf[8]= '-';//基于求解出的字节数组,实例化字符串,指定编码为latin1 return new string (BUF,latin1);} else { byte[]buf = new byte[72];formatUnsignedLong0UTF16(lsb,4,buf,24,12);formatunsignedlong 0 utf 16(LSB & gt;& gt& gt48,4,buf,19,4);formatUnsignedLong0UTF16(msb,4,buf,14,4);formatunsignedlong 0 utf 16(msb & gt;& gt& gt16,4,buf,9,4);formatunsignedlong 0 utf 16(msb & gt;& gt& gt32,4,buf,0,8);StringUTF16.putChar(buf,23,'-');StringUTF16.putChar(buf,18,'-');StringUTF16.putChar(buf,13,'-');StringUTF16.putChar(buf,8,'-');返回新字符串(buf,ut F16);}}/* * *格式化一个无符号长整数,并将其填入字节缓冲区buf。如果len长度超过了输入值的ASCII格式,就用0 *填充,这个方法就是把输入的长整型值val,对应一个bit的长度,填充到字节数组buf中。len控制书写字符的长度。Offset控制写buf *的起始位置而shift参数决定基本格式,4为十六进制,1为二进制,3为8位*/静态void格式无符号long 0 (long val,int shift,byte [] BUF,int offset,int len){ int charpos = offset+len;int radix = 1 & lt& lt移位;int mask = radix-1;do { buf[-charPos]=(byte)integer . digits[((int)val)& amp;面膜];val & gt& gt& gt= shift} while(charPos & gt;偏移);}比较相关方法比较相关方法如下:// hashCode方法是基于mostSigBits和leastSigBits的区别或者得到一个中间变量hilo,然后计算public int hashCode(){ long hilo = most sigbits least sigbits;return((int)(hilo & gt;& gt32)) ^ (int)希洛;}// equals是一个比较方法的例子,直接比较两个UUID的mostSigBits和leastSigBits值,返回真公共布尔equals(object obj){ if((null = = obj)| |(obj . getclass())!= UUID.class))返回falseUUID id =(UUID)obj;return(mostSigBits = = id . mostSigBits & amp;& ampleastSigBits = = id . leastSigBits);}//比较规则是mostSigBits的最高位是最高的,当高位相等时,最大的leastSigBits是big public int compare to(uuid val){//排序是有意设置的,这样uuid//就可以简单地在数字上比较为两个数返回(this . mostSigBits < val . mostSigBits?-1:(this . mostsigbits & gt;val.mostSigBits?1:(this . leasts gibits & lt;val.leastSigBits?-1:(this . least sigbits & gt;val.leastSigBits?1 : 0))));}所有的比较方法都只与mostSigBits和leastSigBits相关。毕竟,这两个长整数存储了UUID实例的所有信息。 看一下UUID的源代码实现,会发现它的实现依赖于几个完整的函数,包括MD5摘要算法和SecureRandom依靠系统随机源生成安全随机数,除了几个精致的比特运算。 UUID之所以能成为标准,是因为它凝聚了计算机领域前辈们多年的成果,所以现在用户可以像写Hello World一样简单地调用UUID.randomUUID()。


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】1556原创ng8文章搜索页面不齐(2024-05-01 14:43)
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部