不同字符串的 UUID 相同

UUID is same from different strings

我有两个不同的字符串,但在解析为 UUID 后似乎是一样的

public static void main(String[] args) {
    try {
        UUID t1 = UUID.fromString("38e1036d-7527-42a3-98ca-f2f19d3155db");
        UUID t2 = UUID.fromString("123438e1036d-7527-42a3-98ca-f2f19d3155db");
        System.out.println(t1.toString().equals(t2.toString()));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

知道这是为什么吗?

一个UUID stores 128 bits的数据。如果你给它更多,它就无法储存它们。我很惊讶它没有给你一个错误,但并不奇怪它会截断更高的位。

int i = 0x38e1036d;
int j = (int) 0x123438e1036dL;
i == j;

第二个组件“7527”的位移消除了您对第一个组件“123438e1036d”所做修改的影响,这会导致生成相同的 UUID。

第一个组件本身的处理是不同的,但是当 uuid 的第二个组件移动时,这种效果就消失了。

"123438e1036d-7527-42a3-98ca-f2f19d3155db"

这不是 UUID。它是“1234”和 UUID 的串联字符串。这里的问题是解析器应该通过抛出异常来告诉你这一点。相反,它会尽最大努力实际找到隐藏在其中某处的 UUID。

从串联字符串中提取 UUID 后,它与第一个 UUID 相同,这是您观察到的正确结果。

我们可以分析解析器(感谢@tim-biegeleisen 提供link):

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

正如我们所见,除了计算连字符限制的组数外,没有任何验证。它只是接受这些群体,然后将它们转移到不同的位置。您在第一组前面添加了额外的字符,这是最重要的部分。它首先被解析和存储,然后它被向上移动并再次向上移动,直到它占据最重要的部分。现在,所有比假设更左边的位都被推出 long 限制,因此它们被完全忽略。

那是因为它是从右往左检查的,只取32个字符作为UUID,其他去掉。一旦32个字符按顺序被占用,它不关心其他的,因为它实现了Serializable接口。

public final class UUID
  extends Object
  implements Serializable, Comparable<UUID>

1234 是从你的第二个 UUID 中删除的。

这是它的代码,它帮助更好

 public static UUID More ...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);
    }

这是 Java 8 中的已知错误,于 2016 年 6 月报告: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8159339

另见 http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8165199(2016 年 8 月报道):

4d4d8f3b-3b81-44f3-968d-d1c1a48b4ac8 is a valid UUID.

4d4d8f-3b3b81-44f3-968d-d1c1a48b4ac8 is not (moved the first dashes two characters to the left)

Calling UUID::fromString() with the invalid one results in an UUID representing 004d4dbf-3b81-44f3-968d-d1c1a48b4ac8.