为什么 java.util.UUID 是可比较的?

Why java.util.UUID is Comparable?

java 中的 UUID 实现了 Comparable。这对我来说有点奇怪,因为在几乎所有情况下,UUID 都是随机生成的(或从某处反序列化,但它们最初可能仍然是随机生成的)。

比较它们似乎没有任何意义,除非您手动生成它们并按顺序递增 LSB/MSB,如果您只想要一个非常大的 ID 号(两个 long 而不是一个),这可能有意义plain long),但这是我能想到的唯一解释。

如果你使用它是有意义的,即作为一个 id。

或者如果有必要将对象保存在树状数据结构中。

这是必需的,例如将它们放入 TreeMap/TreeSet。 RFC 中更相关的引用是

UUIDs are of a fixed size (128 bits) which is reasonably small compared to other alternatives. This lends itself well to sorting, ordering, and hashing of all sorts, storing in databases, simple allocation, and ease of programming in general.

UUIDs, as defined in this document, can also be ordered lexicographically. For a pair of UUIDs, the first one follows the second if the most significant field in which the UUIDs differ is greater for the first UUID. The second precedes the first if the most significant field in which the UUIDs differ is greater for the second UUID.

编辑:正如 Turing85 在评论中指出的那样(后来在 ), Java's java.util.UUID class implements RFC 4122 中指出。这个 RFC 清楚地定义了一个顺序,所以这个 class 实现这样的顺序是有意义的 - 即,通过实施 Comparable.

尽管如此,即使排序不服务于任何 "business" 逻辑,它也有很多其他优点。

首先,它让你保持一致。一个行为确定的系统,其中 X 总是在 Y 之前更容易维护、调试和使用。

其次,排序对于避免死锁非常有帮助。如果你总是以相同的顺序更新实体(并获取所需的锁),你就消除了很多 X 正在等待 Y 的锁,而 Y 本身也在等待 X 的锁的陷阱。

最后 - 为什么不让 UUID 具有可比性?添加的用于实现 compareTo 的字节码增加了 class' 的大小可以忽略不计。如果您不将它用作 Comparable,您几乎不会受到它的影响,并使其实现 Comparable 为 class' 用户提供了更多的灵活性来使用它。

一些 UUID 版本将含义编码到它们的值中:

There are four different basic types of UUIDs: time-based, DCE security, name-based, and randomly generated UUIDs.

正因为如此,比较 UUID 才有意义,因为您可以从它们的值中获得意义。你可以松散地说 "This UUID was made earlier or later" 而不是另一个。

考虑在 Wikipedia 上定义的版本:

  • 版本 1(日期时间和 MAC 地址)
  • 版本 2(日期时间和 MAC 地址,DCE 安全版本)
  • 版本 3 和 5(基于命名空间名称)
  • 版本 4(随机)

你甚至可以在 JavaDoc:

中看到这个

The layout of a variant 2 (Leach-Salz) UUID is as follows: The most significant long consists of the following unsigned fields:

 0xFFFFFFFF00000000 time_low
 0x00000000FFFF0000 time_mid
 0x000000000000F000 version
 0x0000000000000FFF time_hi

How is a Time-based UUID / GUID made

正在查看 Javadoc of UUID, we see that it references IETF RFC 4122: A Universally Unique Identifier (UUID) URN Namespace。在提到的 RFC 中,我们找到了一个与词法等价相关的部分:

Rules for Lexical Equivalence:
   Consider each field of the UUID to be an unsigned integer as shown
   in the table in section Section 4.1.2.  Then, to compare a pair of
   UUIDs, arithmetically compare the corresponding fields from each
   UUID in order of significance and according to their data type.
   Two UUIDs are equal if and only if all the corresponding fields
   are equal.

   [...]

   UUIDs, as defined in this document, can also be ordered
   lexicographically.  For a pair of UUIDs, the first one follows the
   second if the most significant field in which the UUIDs differ is
   greater for the first UUID.  The second precedes the first if the
   most significant field in which the UUIDs differ is greater for
   the second UUID.

这意味着:为了完全实现上述RFC,需要实现定义的顺序。在 Java 中实现这一点的方法是 implements Comparable<...> 或提供 Comparator<...>。由于 RFC 中定义的顺序是 UUID 的 "natural order",因此让 UUID implements Comparable<UUID>.

是合乎逻辑的

至于如何使用这个命令或者是否应该使用这个命令没有争议。我的论点完全基于标准的实施。是否以及如何使用此命令由用户决定。 and 答案给出了为什么人们想要在不明确利用它的情况下定义订单的一些原因。


附录

如果有人支持我的回答,那么也应该支持 。我的答案是后来写的,但遵循相同的论证路线。此外,Alexey 提供了一个示例,说明此顺序可能有何用处。