java as uuid_java UUID 源码学习
UUID
我們平時在使用 UUID 的時候覺得非常簡單,甚至很多人覺得這沒什么技術含量。
那么深入思考一層,UUID 的實現原理是什么?
源碼
類聲明
public final class UUID implements java.io.Serializable, Comparable {
/**
* Explicit serialVersionUID for interoperability.
*/
private static final long serialVersionUID = -4856846361193249489L;
}
實現了兩個常見的接口。
內部變量
/*
* The most significant 64 bits of this UUID.
*
* @serial
*/
private final long mostSigBits;
/*
* The least significant 64 bits of this UUID.
*
* @serial
*/
private final long leastSigBits;
/*
* The random number generator used by this class to create random
* based UUIDs. In a holder class to defer initialization until needed.
*/
private static class Holder {
static final SecureRandom numberGenerator = new SecureRandom();
}
前面2個時位定義。
下面一個 Holder 熟悉單例模式的都知道,這是通過內部靜態類,達到單例效果的一種寫法。
構造器
/**
* Constructs a new {@code UUID} using the specified data. {@code
* mostSigBits} is used for the most significant 64 bits of the {@code
* UUID} and {@code leastSigBits} becomes the least significant 64 bits of
* the {@code UUID}.
*
* @param mostSigBits
* The most significant bits of the {@code UUID}
*
* @param leastSigBits
* The least significant bits of the {@code UUID}
*/
public UUID(long mostSigBits, long leastSigBits) {
this.mostSigBits = mostSigBits;
this.leastSigBits = leastSigBits;
}
這個構造器非常簡單,就是做了下基本屬性的初始化。
還有一個私有的構造器,內容如下:
/*
* Private constructor which uses a byte array to construct the new UUID.
*/
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++)
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;
}
這個方法是直接根據 byte[] 數組內容初始化內部變量。
randomUUID()
這個方法是我們平時用的最多的
UUID.randomUUID().toString()
下面我們一起來看一下這個 randomUUID() 的真面目
/**
* Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
*
* The {@code UUID} is generated using a cryptographically strong pseudo
* random number generator.
*
* @return A randomly generated {@code UUID}
*/
public static UUID randomUUID() {
SecureRandom ng = 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);
}
這里首先通過前面的內部靜態類,獲取一個單例的隨機數生成器。
然后做了 2 個位置的內容變換處理,這個需要一定的位運算知識。
最后在調用前面提到的構造器。
nameUUIDFromBytes(byte[])
/**
* Static factory to retrieve a type 3 (name based) {@code UUID} based on
* the specified byte array.
*
* @param name
* A byte array to be used to construct a {@code UUID}
*
* @return A {@code UUID} generated from the specified array
*/
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);
}
這里是初始化了一個 MD5 的算法類。
后面的處理和上一個方法就類似了。
fromString(String)
源碼如下:
/**
* Creates a {@code UUID} from the string standard representation as
* described in the {@link #toString} method.
*
* @param name
* A string that specifies a {@code UUID}
*
* @return A {@code UUID} with the specified value
*
* @throws IllegalArgumentException
* If name does not conform to the string representation as
* described in {@link #toString}
*
*/
public static UUID fromString(String name) {
String[] components = name.split("-");
if (components.length != 5)
throw new IllegalArgumentException("Invalid UUID string: "+name);
for (int i=0; i<5; i++)
components[i] = "0x"+components[i];
long mostSigBits = Long.decode(components[0]).longValue();
mostSigBits <<= 16;
mostSigBits |= Long.decode(components[1]).longValue();
mostSigBits <<= 16;
mostSigBits |= Long.decode(components[2]).longValue();
long leastSigBits = Long.decode(components[3]).longValue();
leastSigBits <<= 48;
leastSigBits |= Long.decode(components[4]).longValue();
return new UUID(mostSigBits, leastSigBits);
}
這個方法我覺得應該和 toString() 結合起來看,這2個方法應該互為逆過程。
toString()
/**
* Returns a {@code String} object representing this {@code UUID}.
*
*
The UUID string representation is as described by this BNF:
*
* {@code
* UUID = "-" "-"
* "-"
* "-"
*
* time_low = 4*
* time_mid = 2*
* time_high_and_version = 2*
* variant_and_sequence = 2*
* node = 6*
* hexOctet =
* hexDigit =
* "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
* | "a" | "b" | "c" | "d" | "e" | "f"
* | "A" | "B" | "C" | "D" | "E" | "F"
* }
*
* @return A string representation of this {@code UUID}
*/
public String toString() {
return (digits(mostSigBits >> 32, 8) + "-" +
digits(mostSigBits >> 16, 4) + "-" +
digits(mostSigBits, 4) + "-" +
digits(leastSigBits >> 48, 4) + "-" +
digits(leastSigBits, 12));
}
digits()
這里就是把數字轉換為 16 進制
/** Returns val represented by the specified number of hex digits. */
private static String digits(long val, int digits) {
long hi = 1L << (digits * 4);
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
}
感觸
看完之后,是不是覺得并沒有得到精髓呢?
我覺得算法的原理不清楚,單獨看了下源碼,實際上有些問題還是沒有解決。
為什么 UUID 可以保證唯一性?
如何實現自己的,位數更少的 id 算法?
關于這部分將在其他文章中進行補充完善。
拓展閱讀
參考資料
jdk8 源碼
總結
以上是生活随笔為你收集整理的java as uuid_java UUID 源码学习的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: java如何打开整个package_Qu
- 下一篇: 苹果路由器来了-苹果路由器如何设置
