java类uuid源码分析
通用唯一识别码(英语:Universally Unique Identifier,简称UUID)是一种软件建构的标准,亦为自由软件基金会组织在分散式计算环境领域的一部份。
UUID的目的,是让分散式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的UUID。
一组UUID,是由一串16位组(亦称128位)的16进位数字所构成,是故UUID理论上的总数为216 x 8=2128,约等于3.4 x 1038。也就是说若每纳秒产生1兆个UUID,要花100亿年才会将所有UUID用完。所以无需考虑它的重复性。
UUID的标准型式包含32个16进位数字,以连字号分为五段,形式为8-4-4-4-12的32个字符,加上“-”一共是36位,所以咱们可以先取出uuid,再把“-”去掉。
import java.util.UUID;
import org.apache.commons.lang3.RandomStringUtils; public class RandomUtils {
public RandomUtils() {
} public static String generateTicket() {
String ticket = UUID.randomUUID().toString();
return ticket.replaceAll("-", "");
} public static String generateRandomString(int count) {
return RandomStringUtils.random(count, true, true);
} public static String generateRandomNum(int count) {
return RandomStringUtils.random(count, false, true);
} public static String generateRandomFileName() {
return String.join("", generateTicket(), generateRandomString(6));
}
}
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
public static void main(String[] args) {
byte[] b = {0};
System.out.println(UUID.randomUUID());
System.out.println(UUID.randomUUID());
System.out.println(UUID.nameUUIDFromBytes(b));
System.out.println(UUID.nameUUIDFromBytes(b));
}
上边是代码,下边是结果
feb860b4-9bc2-4bab-8844-83c9a6d22aa6
09289276-0af0-4ee8-9e14-e7a0df30aeb8
93b885ad-fe0d-3089-8df6-34904fd59f71
93b885ad-fe0d-3089-8df6-34904fd59f71
比较明显就是randomUUID()目前还是不重复的,
但是nameUUIDFromBytes()已经重复了
解析:看源码是用byte[]的MD5 生成uuid,也就是根据byte[]生成uuid,所以同一个byte[]返回的结果肯定是相同的。
文章目录
一、解释
二、使用示例
三、原理概述
四、源码解析
五、奇技淫巧
六、参考文献
一、解释
维基百科
UUID 是有一定格式的,满足8-4-4-4-12这种格式,如下面这个 UUID :
6b349832-0470-4692-befd-6037b280bbc5
UUID由32 个字母数字字符组成(没有包括连字符),每一个字符是一个16进制的数字(0-f)。UUID 有一定的结构:
注意:16进制用 半个字节 表示,1个字节等于两个半字节,1个字节等于8位,半字节等于4个位。
UUID产生方式:
“版本1” UUID 是根据时间和节点 ID(通常是MAC地址)生成;
“版本2” UUID是根据标识符(通常是组或用户ID)、时间和节点ID生成;
“版本3” 和 “版本5” 确定性UUID 通过散列 (hashing) 名字空间 (namespace) 标识符和名称生成;
“版本4” UUID 使用随机性或伪随机性生成。
二、使用示例
public static void main(String[] args) {
String uuid="";
uuid=UUID.randomUUID().toString();
System.out.println(uuid);
}
结果:
60cc1ff0-4b30-4e35-a0a6-940934ac756b
对,在java中产生 UUID 就是这么简单。
三、原理概述
public static void main(String[] args) {
byte[] randomBytes = new byte[16];//数组每一个元素都为0,所以需要产生随机的16字节
SecureRandom secureRandom=new SecureRandom();
secureRandom.engineNextBytes(randomBytes);
System.out.println(DatatypeConverter.printHexBinary(randomBytes));
/**
*为了满足RFC 4122规范,需要对参数这个16个字节的随机数据进行一些设置。这里我们拿用随机方式产生UUID
* 随机生成 "版本4" UUID。与其他 UUID 一样,4-bit 用于指示 "版本4",2-bit 或 3-bit 用于指示变体(variant)(10 或 110 分别用于 变体 1 和 2)。
* 因此,对于变体1(即大多数 UUID),随机 "版本4" UUID 将具有 6 个预定的变体和版本位,为随机生成的部分留下122位,"版本4" 变体1 UUID 可能共计2的122次方个。
* "版本4" 变体2 UUID (传统GUID)的可能有一半,因为可用的随机位少一个,变量消耗 3 bits。
*/
}
}
运行结果:
82D68D2051EAF9610D36C33642E02594
产生大小为16的字节数组(转换为16进制就是32个字符)
为数组赋值(因为产生的初始数组每一个元素都为0)
其实到这里,我们的唯一id就产生了。只不过 UUID 要满足一定的规范,还有对产生的结果进行一些设置。如设置版本,设置变体。最后,我通过javax.xml.bind包下的DatatypeConverter将我们的字节数组以16进制的方式打印出来。
四、源码解析
UUID
public static UUID randomUUID() {
SecureRandom ng = Holder.numberGenerator;//用于产生byte型的随机数组。
byte[] randomBytes = new byte[16];//产生大小为16的byte数组
ng.nextBytes(randomBytes);//给byte赋随机值。其实调用的是engineNextBytes。
// UUID 要满足一定的规范,还有对产生的结果进行一些设置。如设置版本,设置变体
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= 0x80; /* set to IETF variant */
return new UUID(randomBytes);
}
private UUID(byte[] data) {
long msb = 0;
long lsb = 0;
assert data.length == 16 : "data must be 16 bytes in length";
for (int i=0; i<8; i++)
//为什么要&0xff?是因为要不能或上一个负数byte,char,short的&都是转换为int的
//因为long类型是64位,在进行|运算时,需要补全0才可以运算
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;
}
Java中的UUID是用两个long型的变量mostSigBits 、leastSigBits 来存放UUID的。还有需要注意0xff,这是为了避免|上一个负数。为了阐述不能|一个负数,我举个例子:
最后就导致意外情况
五、奇技淫巧
1、long转16进制
long x=15L;
String temp=Long.toHexString(x);
System.out.println(temp);
结果:f
2、byte数组转16进制
byte[] randomBytes={15,14,12,11,-6};
System.out.println(DatatypeConverter.printHexBinary(randomBytes));
结果:0F0E0C0BFA
六、参考文献
维基百科
JAVA byte数组转化为16进制字符串输出https://blog.csdn.net/wobushixiaobailian/article/details/86065041
java类uuid源码分析的更多相关文章
- 【JAVA】ThreadLocal源码分析
ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...
- 细说并发5:Java 阻塞队列源码分析(下)
上一篇 细说并发4:Java 阻塞队列源码分析(上) 我们了解了 ArrayBlockingQueue, LinkedBlockingQueue 和 PriorityBlockingQueue,这篇文 ...
- Java split方法源码分析
Java split方法源码分析 public String[] split(CharSequence input [, int limit]) { int index = 0; // 指针 bool ...
- 【Java】HashMap源码分析——常用方法详解
上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...
- 【Java】HashMap源码分析——基本概念
在JDK1.8后,对HashMap源码进行了更改,引入了红黑树.在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMa ...
- JDK中String类的源码分析(二)
1.startsWith(String prefix, int toffset)方法 包括startsWith(*),endsWith(*)方法,都是调用上述一个方法 public boolean s ...
- Java并发包源码分析
并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善.现代的PC都有多个CPU或一个CPU中有多个 ...
- Java中ArrayList源码分析
一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...
- Set集合架构和常用实现类的源码分析以及实例应用
说明:Set的实现类都是基于Map来实现的(HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的). (01) Set 是继承于Collection的接口.它是一个不允许 ...
随机推荐
- 3 datax mysql和hive之间相互导入
mysql-->hive 0 参考文档: https://github.com/alibaba/D ...
- Docker学习2-Docker的基本命令与使用
前言: 前些天有人问镜像是什么?容器有是什么?docker对于初学者来说,往往分不清楚镜像和容器,编程语言都知道有一个面向对象,类和实例,类比作镜像,实例比作容器. 有的人蹦着学习的心态的去群里问人, ...
- java,string和list,list和set相互转换
list转string String str= String.join("','", list); list转set Set<String> set = new Has ...
- torch_06_卷积神经网络
1.概述 卷积神经网络的参数,由一些可学习的滤波器集合构成的,每个滤波器在空间上都计较小,但是深度和输入数据的深度保持一致.在前向传播中,让每个滤波器都在输入数据的宽度和高度上滑动(卷积),然后计算整 ...
- 物联网典型场景之智能家电,使用JOSH技术带来的优势和机会~
很多人一直问,用JOSH技术如何改变智能家电,有没有真正的必要? 一部分人的观点:我可以用嵌入式C.汇编完成家电的程序,毕竟这些设备的程序很简单: 另一部分的人:智能家电互相的连接都一直有人在做啊,并 ...
- unix高级环境编程学习笔记第七章(未完)
博客地址:http://www.cnblogs.com/zengjianrong/p/3222081.html 7.1 引言 Main函数调用:命令行参数:存储器布局:如何分配存储器:进程使用env: ...
- The multi-part request contained parameter data (excluding uploaded files) that exceeded the limit for maxPostSize set on the associated connector.
springboot 表单体积过大时报错: The multi-part request contained parameter data (excluding uploaded files) tha ...
- 【生活现场】从诗词大会飞花令到elasticsearch原理解析(转)
add by zhj: 作者是阿里的技术专家,把技术解释的通俗易懂,太牛了.该文转自作者的个人公众号:互联网侦察,里面有很多系列文章, 关于算法,大数据,面试现场三个系列,通过漫画学到知识,太棒了 ...
- Nacos配置中心
本文介绍spring cloud 集成 nacos案例 官方文档:https://nacos.io/zh-cn/docs/what-is-nacos.html](https://nacos.io/zh ...
- Java匹马行天下之JavaSE核心技术——注解
Java注解 一.什么是注解 注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,没有加,则等于没有任何标记,以后,javac编译器.开发工具和其他程序可以通过反射来 ...