Рубрики
Без рубрики

Руководство по UUID на Java

Краткое и практическое введение в UUID на Java.

Автор оригинала: baeldung.

1. Обзор

UUID (Универсальный уникальный идентификатор), также известный как GUID (Глобальный уникальный идентификатор), представляет собой 128-битное значение, уникальное для всех практических целей. Стандартное представление UUID использует шестнадцатеричные цифры (октеты):

123e4567-e89b-12d3-a456-556642440000

UUID состоит из шестнадцатеричных цифр (по 4 символа) и 4 символов” -“, которые делают его длиной, равной 36 символам.

Нулевой UUID-это специальная форма UUID, в которой все биты равны нулю.

В этом уроке мы рассмотрим класс UUID в Java. Сначала мы посмотрим, как использовать сам класс. Затем мы рассмотрим различные типы UUID и то, как мы можем генерировать их в Java.

Дальнейшее чтение:

CharSequence против Строка в Java

Использовать массив char[] Над строкой для манипулирования паролями в Java?

Руководство по пулу строк Java

2. Класс UUID

Класс UUID имеет один конструктор:

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

Если мы хотим использовать этот конструктор, нам нужно предоставить два длинных значения. Однако это требует, чтобы мы сами построили битовый шаблон для UUID.

Для удобства существует три статических метода создания UUID.

Этот первый метод создает UUID версии 3 из заданного массива байтов:

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

Во-вторых, метод randomUUID() создает UUID версии 4. Это самый удобный способ создания UUID :

UUID uuid = UUID.randomUUID();

Третий статический метод возвращает объект UUID с учетом строкового представления данного UUID:

UUID uuid = UUID.fromString(String uuidHexDigitString);

Давайте теперь посмотрим, как структурирован UUID.

3. Структура

Давайте возьмем пример UUID:

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

3.1. Вариант UUID

A представляет вариант, определяющий расположение UUID. Все остальные биты в UUID зависят от настройки битов в поле вариант. Вариант определяется тремя наиболее значимыми битами:

  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)

Значение A в упомянутом UUID равно “a”. Двоичный эквивалент “а”) показывает вариант как 2.

3.2. Версия UUID

B представляет версию. Версия в упомянутом UUID (значение B ) равна 4.

Java предоставляет методы для получения варианта и версии UUID:

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

Это пять различных версий для варианта 2 Uuid: основанная на времени (UUID v1), безопасность DCE (UUIDv2), основанная на имени (UUID v3 и UUIDv5) и случайная (UUIDv4).

Java предоставляет реализацию для v3 и v4, но также предоставляет конструктор для создания любого типа UUID:

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

4. Версии UUID

4.1. Версия 1

UUID версии 1 основан на текущей метке времени, измеренной в единицах 100 наносекунд с 15 октября 1582 года, связанной с MAC-адресом устройства, на котором создается UUID.

Если вас беспокоит конфиденциальность, UUID версии 1 может быть сгенерирован со случайным 48-битным номером вместо MAC-адреса. В этой статье мы рассмотрим эту альтернативу.

Во-первых, мы сгенерируем 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;
}

Затем мы можем передать эти два значения конструктору UUID:

public static UUID generateType1UUID() {

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

    return new UUID(most64SigBits, least64SigBits);
}

4.2. Версия 2

Версия 2 основана на метке времени и MAC-адресе. Однако RFC 4122 не указывает точных деталей генерации, поэтому мы не будем рассматривать реализацию в этой статье.

4.3. Версии 3 и 5

UUID генерируются с использованием хэша пространства имен и имени. Идентификаторами пространства имен являются UUID, такие как Система доменных имен (DNS), идентификаторы объектов (OID), URL-адреса и т. Д.

UUID = hash(NAMESPACE_IDENTIFIER + NAME)

Единственное различие между UUIDv3 и UUIDv5 заключается в алгоритме хеширования — v3 использует MD5 (128 бит), в то время как v5 использует SHA-1 (160 бит).

Проще говоря, мы усекаем полученный хэш до 128 бит, а затем заменяем 4 бита для версии и 2 бита для варианта.

Давайте сгенерируем UUID типа 3:

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

UUID uuid = UUID.nameUUIDFromBytes(result);

Здесь важно отметить, что шестнадцатеричная строка для пространства имен сначала должна быть преобразована в массив байтов.

Наконец, Java не предоставляет реализацию для типа 5. Проверьте исходный код репозиторий для UUIDv5.

4.4. Версия 4

Реализация UUID v4 использует случайные числа в качестве источника. Реализация Java-это SecureRandom , которая использует непредсказуемое значение в качестве начального для генерации случайных чисел, чтобы уменьшить вероятность столкновений.

Давайте сгенерируем UUID версии 4:

UUID uuid = UUID.randomUUID();

Давайте сгенерируем уникальный ключ, используя “SHA-256” и случайный UUID:

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

5. Заключение

В этой статье мы рассмотрели, как структурирован UUID и какие существуют варианты и версии.

Мы также узнали, для каких версий Java предоставляет готовую реализацию, и рассмотрели примеры кода для создания других версий.

И, как всегда, исходный код реализации доступен на GitHub .