All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.geewit.utils.uuid.UUID Maven / Gradle / Ivy

There is a newer version: 2.0.95
Show newest version
package io.geewit.utils.uuid;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * 来自 JDK {@link java.util.UUID} 去掉 ‘-’
 *
 * @author geewit
 * @since 2015-05-18
 */
@SuppressWarnings({"unused"})
public class UUID implements java.io.Serializable, Comparable {
    private static final long serialVersionUID = 1L;

    /*
     * 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();
    }

    // Constructors and Factories

    /*
     * 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;
    }

    /**
     * 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;
    }

    /**
     * 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); } /** * 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); } /** * 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) { if(name.length() != 32) { throw new IllegalArgumentException("Invalid UUID string: " + name); } String[] components = new String[5]; for (int i = 0; i < 5; i++) { switch (i) { case 0: { components[i] = "0x" + name.substring(0, 8); break; } case 1: { components[i] = "0x" + name.substring(8, 12); break; } case 2: { components[i] = "0x" + name.substring(12, 16); break; } case 3: { components[i] = "0x" + name.substring(16, 20); break; } case 4: { components[i] = "0x" + name.substring(20, 32); break; } } } long mostSigBits = Long.decode(components[0]); mostSigBits <<= 16; mostSigBits |= Long.decode(components[1]); mostSigBits <<= 16; mostSigBits |= Long.decode(components[2]); long leastSigBits = Long.decode(components[3]); leastSigBits <<= 48; leastSigBits |= Long.decode(components[4]); return new UUID(mostSigBits, leastSigBits); } // Field Accessor Methods /** * Returns the least significant 64 bits of this UUID's 128 bit value. * * @return The least significant 64 bits of this UUID's 128 bit value */ public long getLeastSignificantBits() { return leastSigBits; } /** * Returns the most significant 64 bits of this UUID's 128 bit value. * * @return The most significant 64 bits of this UUID's 128 bit value */ public long getMostSignificantBits() { return mostSigBits; } /** * The version number associated with this {@code UUID}. The version * number describes how this {@code UUID} was generated. *

* The version number has the following meaning: *

    *
  • 1 Time-based UUID *
  • 2 DCE security UUID *
  • 3 Name-based UUID *
  • 4 Randomly generated UUID *
* * @return The version number of this {@code UUID} */ public int version() { // Version is bits masked by 0x000000000000F000 in MS long return (int) ((mostSigBits >> 12) & 0x0f); } /** * The variant number associated with this {@code UUID}. The variant * number describes the layout of the {@code UUID}. *

* The variant number has the following meaning: *

    *
  • 0 Reserved for NCS backward compatibility *
  • 2 IETF RFC 4122 * (Leach-Salz), used by this class *
  • 6 Reserved, Microsoft Corporation backward compatibility *
  • 7 Reserved for future definition *
* * @return The variant number of this {@code UUID} */ public int variant() { // This field is composed of a varying number of bits. // 0 - - Reserved for NCS backward compatibility // 1 0 - The IETF aka Leach-Salz variant (used by this class) // 1 1 0 Reserved, Microsoft backward compatibility // 1 1 1 Reserved for future definition. return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); } /** * The timestamp value associated with this UUID. * *

The 60 bit timestamp value is constructed from the time_low, * time_mid, and time_hi fields of this {@code UUID}. The resulting * timestamp is measured in 100-nanosecond units since midnight, * October 15, 1582 UTC. * *

The timestamp value is only meaningful in a time-based UUID, which * has version type 1. If this {@code UUID} is not a time-based UUID then * this method throws UnsupportedOperationException. * * @return The timestamp of this {@code UUID}. * @throws UnsupportedOperationException If this UUID is not a version 1 UUID */ public long timestamp() { if (version() != 1) { throw new UnsupportedOperationException("Not a time-based UUID"); } return (mostSigBits & 0x0FFFL) << 48 | ((mostSigBits >> 16) & 0x0FFFFL) << 32 | mostSigBits >>> 32; } /** * The clock sequence value associated with this UUID. * *

The 14 bit clock sequence value is constructed from the clock * sequence field of this UUID. The clock sequence field is used to * guarantee temporal uniqueness in a time-based UUID. * *

The {@code clockSequence} value is only meaningful in a time-based * UUID, which has version type 1. If this UUID is not a time-based UUID * then this method throws UnsupportedOperationException. * * @return The clock sequence of this {@code UUID} * @throws UnsupportedOperationException If this UUID is not a version 1 UUID */ public int clockSequence() { if (version() != 1) { throw new UnsupportedOperationException("Not a time-based UUID"); } return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); } /** * The node value associated with this UUID. * *

The 48 bit node value is constructed from the node field of this * UUID. This field is intended to hold the IEEE 802 address of the machine * that generated this UUID to guarantee spatial uniqueness. * *

The node value is only meaningful in a time-based UUID, which has * version type 1. If this UUID is not a time-based UUID then this method * throws UnsupportedOperationException. * * @return The node value of this {@code UUID} * @throws UnsupportedOperationException If this UUID is not a version 1 UUID */ public long node() { if (version() != 1) { throw new UnsupportedOperationException("Not a time-based UUID"); } return leastSigBits & 0x0000FFFFFFFFFFFFL; } // Object Inherited Methods /** * 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)); } /** * 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); } /** * Returns a hash code for this {@code UUID}. * * @return A hash code value for this {@code UUID} */ public int hashCode() { long hilo = mostSigBits ^ leastSigBits; return ((int) (hilo >> 32)) ^ (int) hilo; } /** * Compares this object to the specified object. The result is {@code * true} if and only if the argument is not {@code null}, is a {@code UUID} * object, has the same variant, and contains the same value, bit for bit, * as this {@code UUID}. * * @param obj The object to be compared * @return {@code true} if the objects are the same; {@code false} * otherwise */ public boolean equals(Object obj) { if ((null == obj) || (obj.getClass() != UUID.class)) { return false; } UUID id = (UUID) obj; return mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits; } // Comparison Operations /** * Compares this UUID with the specified UUID. * *

The first of two UUIDs is greater than the second if the most * significant field in which the UUIDs differ is greater for the first * UUID. * * @param val {@code UUID} to which this {@code UUID} is to be compared * @return -1, 0 or 1 as this {@code UUID} is less than, equal to, or * greater than {@code val} */ public int compareTo(UUID val) { // The ordering is intentionally set up so that the UUIDs // can simply be numerically compared as two numbers return Long.compare(this.leastSigBits, val.leastSigBits); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy