Guide to UUID in Java – Java中的UUID指南

最后修改: 2017年 5月 30日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

UUID (Universally Unique Identifier), also known as GUID (Globally Unique Identifier) represents a 128-bit long value that is unique for all practical purposes. The standard representation of the UUID uses hex digits (octets):

UUID (Universally Unique Identifier),也被称为GUID(Globally Unique Identifier),代表一个128位的长值,在所有实际用途中都是唯一的。UUID的标准表示法使用十六进制数字(八位数):

123e4567-e89b-12d3-a456-556642440000

A UUID is made up of hex digits  (4 chars each) along with 4 “-” symbols, which make its length equal to 36 characters.

UUID由十六进制数字(每个4个字符)和4个”-“符号组成,这使得其长度等于36个字符。

The Nil UUID is a special form of UUID in which all bits are set to zero.

无UUID是UUID的一种特殊形式,其中所有位都被设置为零。

In this tutorial, we will have a look at the UUID class in Java.  First, we’ll see how to use the class itself. Then we’ll look at the different types of UUIDs and how we can generate them in Java.

在本教程中,我们将看看Java中的UUID类。 首先,我们将看到如何使用这个类本身。然后,我们将看看UUID的不同类型以及如何在Java中生成它们。

2. The UUID Class

2.UID

The UUID class has a single constructor:

UUID类有一个单一的构造函数。

UUID uuid = new UUID(long mostSignificant64Bits, long leastSignificant64Bits);

If we want to use this constructor, we need to provide two long values. However, it requires us to construct the bit-pattern for the UUID ourselves.

如果我们想使用这个构造函数,我们需要提供两个长值。然而,它要求我们自己构建UUID的位模式。

For convenience, there are three static methods to create a UUID.

为了方便起见,有三种静态方法来创建UUID。

This first method creates a version 3 UUID from the given byte array:

这第一个方法从给定的字节数组中创建一个版本3的UUID。

UUID uuid = UUID.nameUUIDFromBytes(byte[] bytes);

Second, the randomUUID() method creates a version 4 UUID. This is the most convenient way of creating a UUID:

其次,randomUUID()方法创建了一个版本4的UUID。这是创建UUID的最方便的方法

UUID uuid = UUID.randomUUID();

The third static method returns a UUID object given the string representation of a given UUID:

第三个静态方法返回一个UUID对象,给定的UUID的字符串表示。

UUID uuid = UUID.fromString(String uuidHexDigitString);

Let’s now look at how a UUID is structured.

现在让我们来看看UUID是如何结构的。

3. Structure

3.结构

Let’s take the example UUID:

让我们以UUID为例。

123e4567-e89b-42d3-a456-556642440000
xxxxxxxx-xxxx-Bxxx-Axxx-xxxxxxxxxxxx

3.1. UUID Variant

UUID变体

A represents the variant that determines the layout of the UUID. All other bits in the UUID depend on the setting of the bits in the variant field. The variant is determined by the three most significant bits of A:

A代表决定UUID布局的变体。UUID中的所有其他位都取决于变体字段中的位的设置。变体是由A的三个最重要的位决定的。

  MSB1    MSB2    MSB3
   0       X       X     reserved (0)
   1       0       X     current variant (2)
   1       1       0     reserved for Microsoft (6)
   1       1       1     reserved for future (7)

The value of A in the mentioned UUID is “a”. The binary equivalent of “a” (=10xx) shows the variant as 2.

上述UUID中A的值是 “a”。a “的二进制等价物(=10xx)显示变体为2。

3.2. UUID Version

3.2.UUID版本

B represents the version. The version in the mentioned UUID (value of B) is 4.

B代表版本。上述UUID中的版本(B的值)是4。

Java provides methods for getting variant and version of UUID:

Java提供了获取UUID的变体和版本的方法:

UUID uuid = UUID.randomUUID();
int variant = uuid.variant();
int version = uuid.version();

These are five different versions for variant 2 UUIDs: Time Based (UUIDv1), DCE Security (UUIDv2), Name Based (UUIDv3 and UUIDv5), and Random (UUIDv4).

这些是变体2 UUIDs的五个不同版本。基于时间(UUIDv1),DCE安全(UUIDv2),基于名称(UUIDv3和UUIDv5),和随机(UUIDv4)。

Java provides an implementation for the v3 and v4 but also provides a constructor for generating any type of UUID:

Java为v3和v4提供了一个实现,但也提供了一个构造器,用于生成任何类型的UUID。

UUID uuid = new UUID(long mostSigBits, long leastSigBits);

4. The UUID Versions

4.UUID版本

4.1. Version 1

4.1.版本1

UUID version 1 is based on the current timestamp, measured in units of 100 nanoseconds from October 15, 1582, concatenated with the MAC address of the device where the UUID is created.

UUID版本1是基于当前的时间戳,从1582年10月15日开始,以100纳秒为单位,与创建UUID的设备的MAC地址相连接。

If privacy is a concern, UUID version 1 can alternatively be generated with a random 48-bit number instead of the MAC address. In this article, we’ll look at this alternative.

如果担心隐私问题,UUID版本1可以用一个随机的48位数字代替MAC地址来生成。在这篇文章中,我们将看看这个替代方案。

First, we’ll generate the 64 least and most significant bits as long values:

首先,我们将生成64个最小和最重要的比特作为长值。

private static long get64LeastSignificantBitsForVersion1() {
    Random random = new Random();
    long random63BitLong = random.nextLong() & 0x3FFFFFFFFFFFFFFFL;
    long variant3BitFlag = 0x8000000000000000L;
    return random63BitLong + variant3BitFlag;
}

private static long get64MostSignificantBitsForVersion1() {
    LocalDateTime start = LocalDateTime.of(1582, 10, 15, 0, 0, 0);
    Duration duration = Duration.between(start, LocalDateTime.now());
    long seconds = duration.getSeconds();
    long nanos = duration.getNano();
    long timeForUuidIn100Nanos = seconds * 10000000 + nanos * 100;
    long least12SignificatBitOfTime = (timeForUuidIn100Nanos & 0x000000000000FFFFL) >> 4;
    long version = 1 << 12;
    return 
      (timeForUuidIn100Nanos & 0xFFFFFFFFFFFF0000L) + version + least12SignificatBitOfTime;
}

We can then pass these two values to the constructor of the UUID:

然后我们可以将这两个值传递给UUID的构造函数。

public static UUID generateType1UUID() {

    long most64SigBits = get64MostSignificantBitsForVersion1();
    long least64SigBits = get64LeastSignificantBitsForVersion1();

    return new UUID(most64SigBits, least64SigBits);
}

4.2. Version 2

4.2.版本2

Version 2 is based on a timestamp and the MAC address as well. However, RFC 4122 does not specify the exact generation details, so we won’t look at an implementation in this article.

第二版也是基于一个时间戳和MAC地址。然而,RFC 4122并没有指定确切的生成细节,所以我们不会在本文中看一个实现。

4.3. Versions 3 and 5

4.3.版本3和5

The UUIDs are generated using the hash of namespace and name. The namespace identifiers are UUIDs like Domain Name System (DNS), Object Identifiers (OIDs), URLs, etc.

UUIDs是使用命名空间和名称的哈希值生成的。命名空间标识符是UUID,如域名系统(DNS)、对象标识符(OID)、URL等。

UUID = hash(NAMESPACE_IDENTIFIER + NAME)

The only difference between UUIDv3 and UUIDv5 is the Hashing Algorithm — v3 uses MD5 (128 bits), while v5 uses SHA-1 (160 bits).

UUIDv3和UUIDv5之间的唯一区别是哈希算法 – v3使用MD5(128位),而v5使用SHA-1(160位)。

Simply put, we truncate the resulting hash to 128 bits and then replace 4 bit for the version and 2 bit for the variant.

简单地说,我们将得到的哈希值截断为128位,然后将4位替换为版本,2位替换为变体。

Let’s generate type 3 UUID:

让我们生成3类UUID:

byte[] nameSpaceBytes = bytesFromUUID(namespace);
byte[] nameBytes = name.getBytes("UTF-8");
byte[] result = joinBytes(nameSpaceBytes, nameBytes);

UUID uuid = UUID.nameUUIDFromBytes(result);

Here, it’s important to note that the hex string for the namespace first needs to be converted to a byte array.

这里,需要注意的是,命名空间的十六进制字符串首先需要转换为字节数组。

Finally, Java doesn’t provide the implementation for type 5. Check our source code repository for the UUIDv5.

最后,Java没有提供类型5的实现。请查看我们的源代码资源库,了解UUIDv5的情况。

4.4. Version 4

4.4.版本4

The UUIDv4 implementation uses random numbers as the source. The Java implementation is SecureRandom, which uses an unpredictable value as the seed to generate random numbers to reduce the chance of collisions.

UUIDv4的实现使用随机数作为来源。Java的实现是SecureRandom,它使用一个不可预测的值作为种子来生成随机数以减少碰撞的机会。

Let’s generate version 4 UUID:

让我们生成第4版UUID。

UUID uuid = UUID.randomUUID();

Let’s generate a unique key using “SHA-256” and a random UUID:

让我们用 “SHA-256 “和一个随机的UUID生成一个唯一的密钥。

MessageDigest salt = MessageDigest.getInstance("SHA-256");
salt.update(UUID.randomUUID().toString().getBytes("UTF-8"));
String digest = bytesToHex(salt.digest());

5. Conclusion

5.结论

In this article, we saw how a UUID is structured and which variants and versions there are.

在这篇文章中,我们看到了UUID的结构以及有哪些变体和版本。

We also learned for which versions Java provides an out-of-the-box implementation and looked at code examples to generate the other versions.

我们还了解了哪些版本的Java提供了开箱即用的实现,并查看了生成其他版本的代码示例。

And as always, the source code of implementation is available over on GitHub.

一如既往,实施的源代码可在GitHub上获得over