<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          可笑,你竟然不知道 Java 如何生成 UUID

          共 4564字,需瀏覽 10分鐘

           ·

          2020-08-02 11:14

          一個調(diào)皮的讀者在之前我寫的“我去”系列文章里留言調(diào)侃說,“二哥,你是無中生小王嗎?”不不不,其實真不是的,小王是真實存在的,他一直和我并肩作戰(zhàn),不辭辛勞,讓我既愛又恨。我愛他,因為他兢兢業(yè)業(yè),任勞任怨,和我心有靈犀;我恨他,因為他時不時會中二一下,問我一些可笑的問題,比如說這次,“二哥,你能給我說說 Java 如何生成 UUID 嗎?”

          UUID,全名叫做 Universally Unique Identifier,也就是通用唯一標(biāo)識符的意思。有時候,也叫做全局唯一標(biāo)識符,英文全名叫做 Globally Unique Identifier,簡拼為 GUID。

          來看一下 UUID 的格式:

          123e4567-e89b-12d3-a456-556642440000
          xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

          由四個中劃線“-”隔開,第一部分的長度為 8,第二部分和第三部分的長度為 4,第四部分的長度為 12,總長度為 36,是固定的。每一部分都是一個十六進(jìn)制的數(shù)字,注意并不是隨機(jī)的任意字母+數(shù)字的字符串。

          M 表示 UUID 的版本,N 為 UUID 的變體(Variants)。

          M 的值有 5 個可選項:

          • 版本 1:UUID 是根據(jù)時間和 MAC 地址生成的;

          • 版本 2:UUID 是根據(jù)標(biāo)識符(通常是組或用戶 ID)、時間和節(jié)點(diǎn) ID生成的;

          • 版本 3:UUID 是通過散列(MD5 作為散列算法)名字空間(namespace)標(biāo)識符和名稱生成的;

          • 版本 4 - UUID 使用隨機(jī)性或偽隨機(jī)性生成;

          • 版本 5 類似于版本 3(SHA1 作為散列算法)。

          為了能兼容過去的 UUID,以及應(yīng)對未來的變化,因此有了變體(Variants)這一概念。

          目前已知的變體有下面 4 種:

          • 變體 0:格式為 0xxx,為了向后兼容預(yù)留。

          • 變體 1:格式為 10xx,當(dāng)前正在使用的。

          • 變體 2:格式為 11xx,為早期微軟的 GUID 預(yù)留。

          • 變體 3:格式為 111x,為將來的擴(kuò)展預(yù)留,目前暫未使用。

          在上例中,M 是 1,N 是 a(二進(jìn)制為 1010,符合 10xx 的格式),這就意味著這個 UUID 是“版本 1”、“變體 1”的 UUID。

          目前大多數(shù)使用的 UUID 大都是變體 1,N 的取值是 8、9、a、b 中的一個。

          System.out.println(Integer.toBinaryString(Integer.valueOf("8",16)));?//?1000
          System.out.println(Integer.toBinaryString(Integer.valueOf("a",16)));?//?1010
          System.out.println(Integer.toBinaryString(Integer.valueOf("9",16)));?//?1001
          System.out.println(Integer.toBinaryString(Integer.valueOf("b",16)));?//?1011

          8 的二進(jìn)制為 1000,9 的二進(jìn)制為 1001,a 的二進(jìn)制為 1010,b 的二進(jìn)制為 1011,都符合 10xx 的格式。

          由于 UUID 是全局唯一的,重復(fù) UUID 的概率接近零,可以忽略不計。所以 Java 的 UUID 通??捎糜谝韵碌胤剑?/p>

          • 隨機(jī)生成的文件名;

          • Java Web 應(yīng)用程序的 sessionID;

          • 數(shù)據(jù)庫表的主鍵;

          • 事務(wù) ID(UUID 生成算法非常高效,每臺計算機(jī)每秒高達(dá) 1000 萬次)。

          在 Java 中,就有一個叫 UUID 的類,在 java.util 包下。

          package?java.util;
          public?final?class?UUID?implements?java.io.Serializable,?Comparable<UUID>?{
          }

          該類只有一個構(gòu)造方法:

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

          要使用構(gòu)造方法創(chuàng)建 UUID 對象的話,就需要傳遞兩個參數(shù),long 型的最高位 UUID 和最低位的 UUID。

          long?msb?=?System.currentTimeMillis();
          long?lsb?=?System.currentTimeMillis();
          UUID?uuidConstructor?=?new?UUID(msb,?lsb);
          System.out.println("UUID?:?"+uuidConstructor);

          輸出結(jié)果如下所示:

          UUID?:?00000173-8efd-1b7c-0000-01738efd1b7c

          UUID 類提供了一個靜態(tài)方法 randomUUID()

          public?static?UUID?randomUUID()?{
          ????SecureRandom?ng?=?UUID.Holder.numberGenerator;

          ????byte[]?randomBytes?=?new?byte[16];
          ????ng.nextBytes(randomBytes);
          ????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);
          }

          randomUUID() 方法生成了一個版本 4 的 UUID,這也是生成 UUID 最方便的方法。如果只使用原生 JDK 的話,基本上都用的這種方式。

          示例如下:

          UUID?uuid4?=?UUID.randomUUID();
          int?version4?=?uuid4.version();
          System.out.println("UUID:"+?uuid4+"?版本?"?+?version4);

          程序輸出結(jié)果如下所示:

          UUID:8c943921-d83e-424a-a627-a12d3cb474db?版本?4

          除此之外,UUID 類還提供了另外兩個靜態(tài)方法,其一是 nameUUIDFromBytes()

          public?static?UUID?nameUUIDFromBytes(byte[]?name)?{
          ????MessageDigest?md;
          ????try?{
          ????????md?=?MessageDigest.getInstance("MD5");
          ????}?catch?(NoSuchAlgorithmException?nsae)?{
          ????????throw?new?InternalError("MD5?not?supported",?nsae);
          ????}
          ????byte[]?md5Bytes?=?md.digest(name);
          ????md5Bytes[6]??&=?0x0f;??/*?clear?version????????*/
          ????md5Bytes[6]??|=?0x30;??/*?set?to?version?3?????*/
          ????md5Bytes[8]??&=?0x3f;??/*?clear?variant????????*/
          ????md5Bytes[8]??|=?0x80;??/*?set?to?IETF?variant??*/
          ????return?new?UUID(md5Bytes);
          }

          nameUUIDFromBytes() 會生成一個版本 3 的 UUID,不過需要傳遞一個名稱的字節(jié)數(shù)組作為參數(shù)。

          示例如下:

          UUID?uuid3?=?UUID.nameUUIDFromBytes("test".getBytes());
          int?version3?=?uuid3.version();
          System.out.println("UUID:"+?uuid3+"?版本?"?+?version3);

          程序輸出結(jié)果如下所示:

          UUID:098f6bcd-4621-3373-8ade-4e832627b4f6?版本?3

          其二是 fromString()

          public?static?UUID?fromString(String?name)?{
          ????int?len?=?name.length();
          ????if?(len?>?36)?{
          ????????throw?new?IllegalArgumentException("UUID?string?too?large");
          ????}

          ????int?dash1?=?name.indexOf('-',?0);
          ????int?dash2?=?name.indexOf('-',?dash1?+?1);
          ????int?dash3?=?name.indexOf('-',?dash2?+?1);
          ????int?dash4?=?name.indexOf('-',?dash3?+?1);
          ????int?dash5?=?name.indexOf('-',?dash4?+?1);

          ????//?For?any?valid?input,?dash1?through?dash4?will?be?positive?and?dash5
          ????//?negative,?but?it's?enough?to?check?dash4?and?dash5:
          ????//?-?if?dash1?is?-1,?dash4?will?be?-1
          ????//?-?if?dash1?is?positive?but?dash2?is?-1,?dash4?will?be?-1
          ????//?-?if?dash1?and?dash2?is?positive,?dash3?will?be?-1,?dash4?will?be
          ????//???positive,?but?so?will?dash5
          ????if?(dash4?0?||?dash5?>=?0)?{
          ????????throw?new?IllegalArgumentException("Invalid?UUID?string:?"?+?name);
          ????}

          ????long?mostSigBits?=?Long.parseLong(name,?0,?dash1,?16)?&?0xffffffffL;
          ????mostSigBits?<<=?16;
          ????mostSigBits?|=?Long.parseLong(name,?dash1?+?1,?dash2,?16)?&?0xffffL;
          ????mostSigBits?<<=?16;
          ????mostSigBits?|=?Long.parseLong(name,?dash2?+?1,?dash3,?16)?&?0xffffL;
          ????long?leastSigBits?=?Long.parseLong(name,?dash3?+?1,?dash4,?16)?&?0xffffL;
          ????leastSigBits?<<=?48;
          ????leastSigBits?|=?Long.parseLong(name,?dash4?+?1,?len,?16)?&?0xffffffffffffL;

          ????return?new?UUID(mostSigBits,?leastSigBits);
          }

          fromString() 方法會生成一個基于指定 UUID 字符串的 UUID 對象,如果指定的 UUID 字符串不符合 UUID 的格式,將拋出 IllegalArgumentException 異常。

          示例如下:

          UUID?uuid?=?UUID.fromString("38400000-8cf0-11bd-b23e-10b96e4ef00d");
          int?version?=?uuid.version();
          System.out.println("UUID:"+?uuid+"?版本?"?+?version);

          程序輸出結(jié)果如下所示:

          UUID:38400000-8cf0-11bd-b23e-10b96e4ef00d?版本?1

          除了使用 JDK 原生的 API 之外,還可以使用 com.fasterxml.uuid.Generators,需要先在項目中加入該類的 Maven 依賴。

          <dependency>
          ????<groupId>com.fasterxml.uuidgroupId>
          ????<artifactId>java-uuid-generatorartifactId>
          ????<version>3.1.4version>
          dependency>

          然后我們來看一下如何使用它:

          /**
          ?*?@author?沉默王二,一枚有趣的程序員
          ?*/

          public?class?UUIDVersionExample?{
          ????public?static?void?main(String[]?args)?{
          ????????UUID?uuid1?=?Generators.timeBasedGenerator().generate();
          ????????System.out.println("UUID?:?"+uuid1);
          ????????System.out.println("UUID?版本?:?"+uuid1.version());

          ????????UUID?uuid2?=?Generators.randomBasedGenerator().generate();
          ????????System.out.println("UUID?:?"+uuid2);
          ????????System.out.println("UUID?版本?:?"+uuid2.version());
          ????}
          }

          Generators.timeBasedGenerator().generate() 可用于生成版本 1 的 UUID,Generators.randomBasedGenerator().generate() 可用于生成版本 4 的 UUID。

          來看一下輸出結(jié)果:

          UUID?:?ebee82f5-cfd2-11ea-82a7-8536e13d4951
          UUID?版本?:?1
          UUID?:?d2ccc752-c824-4bbc-8cc7-52c8246bbc6a
          UUID?版本?:?4

          好了,我想關(guān)于 UUID 的一切,我都已經(jīng)說明白了。趕緊把這篇文章先發(fā)給小王預(yù)覽一下,讓他漲漲見識。

          ------------------

          公眾號:沉默王二(ID:cmower)
          CSDN:沉默王二
          這是一個有顏值卻靠才華吃飯的程序員,你知道,他的文章風(fēng)趣幽默,讀起來就好像花錢一樣爽快。

          長按下圖二維碼關(guān)注,你將感受到一個有趣的靈魂,且每篇文章都有干貨。

          ------------------


          原創(chuàng)不易,莫要白票,如果覺得有點(diǎn)用的話,請毫不留情地素質(zhì)三連吧,分享、點(diǎn)贊、在看,我不挑,因為這將是我寫作更多優(yōu)質(zhì)文章的最強(qiáng)動力。

          PS:8 月份第一天,希望小伙伴們在新的一個月份里都能夠順順利利,加油!

          瀏覽 21
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  AAA片| 99热7| 欧美操日本 | 日韩有码电影中文字幕 | 91麻豆精品国产91久久久 |