Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are two different java.util.UUID objects comparing as equal?

Tags:

java

uuid

I have created two instances of java.util.UUID as given below. One is created from UUID.randomUUID() and the other is the same but with some additional digits prepended to the beginning. When these are compared using the UUID.equals method it returns true:

UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.fromString("12345"+uuid1.toString());
System.out.println(uuid1.equals(uuid2));  // this gives true.

I think the added digits are being discarded and both give the same UUID string value. Why this is happening?

like image 736
Arun Prabhath Avatar asked Jun 13 '17 10:06

Arun Prabhath


People also ask

Can UUID be compared?

The compareTo() method of UUID class in Java is used to compare one UUID value with another specified UUID. It returns -1 if this UUID is less than the value, 0 if this UUID is equal to the value, and 1 if this UUID is greater than the value.

Is Java UUID really unique?

A UUID is 36 characters long unique number. It is also known as a Globally Unique Identifier (GUID). A UUID is a class that represents an immutable Universally Unique Identifier (UUID). A UUID represents a 128-bit long value that is unique to all practical purpose.

Can Java UUID be duplicate?

According to wikipedia, regarding the probability of duplicates in random UUIDs: Only after generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%.

What is the use of Java Util UUID?

A UUID represents a 128-bit value. It is used for for creating random file names, session id in web application, transaction id etc. There are four different basic types of UUIDs: time-based, DCE security, name-based, and randomly generated UUIDs.

How do I compare two UUIDs in Java?

The compareTo () method of UUID class in Java is used to compare one UUID value with another specified UUID. It returns -1 if this UUID is less than the value, 0 if this UUID is equal to the value, and 1 if this UUID is greater than the value.

How to compare the equality of two objects in Java?

The equals () method of the Object class compare the equality of two objects. The two objects will be equal if they share the same memory address. The method parses a reference object as a parameter. It returns true if the objects are equal, else returns false.

What is the difference between equal () and identical () methods in Java?

Whereas the equals () method compares two objects. Objects are equal when they have the same state (usually comparing variables). Objects are identical when they share the class identity.

What is the difference between UUIDs and equals ()?

That is, it checks to see if these two objects are literally the same spot in memory. .equals () will check for actual object equivalence. And, the Javadoc for UUID goes into great detail to explain when two UUID instances are equivalent. Show activity on this post.


1 Answers

In the UUID.fromString(...) method you have this:

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);
}

The first thing it does it to separate the parts of the UUID into components, then it will create two longs. Here you changed only the first component of the UUID by adding leading characters, your UUID string is for example "12345894ff97a-039b-47fe-8a72-950b7766d50c". So the first component is "12345894ff97a", when it will do

long mostSigBits = Long.decode(components[0]).longValue();

Then you will have "320256540146042" which actual HEX representation is "12345894ff97a", then you have a bit operation that will shift the long 16 bits to the left:

mostSigBits <<= 16;

This will result in "2541588541301456896" which actual HEX representation is "2345894ff97a0000" (we moved 16 bits so 4 hex chars) and you start to see what is happening, see the long format is only 64 bits, so when shifting the bits some are lost, here the first character "1" is lost. After that in the freed space it will add the second component:

mostSigBits |= Long.decode(components[1]).longValue();

This will result in "2541588541301457819" which actual HEX representation is "2345894ff97a039b", then it will shift the long 16 bits to the left again:

mostSigBits <<= 16;

This will result in "-8552342864911466496" which actual HEX representation is "894ff97a039b0000" and here your leading characters are all lost because of the long 64 bits size.

I don't need to explain the rest of the method (at the end mostSigBits is "894ff97a039b47fe" and leastSigBits is "8a72950b7766d50c"), you can already understand that any leading character added to an UUID will be lost when calling UUID.fromString(..) since only the last 8 hex characters (32 bits) are going to be considered, the rest is going to be lost.

like image 139
Nyamiou The Galeanthrope Avatar answered Nov 15 '22 22:11

Nyamiou The Galeanthrope