问题原因
你所看到的是一个已知的bug,这个bug不会被修复以保持向后兼容性。
详情请见JDK-7025832:
虽然这个bug确实存在,compareTo
方法的实现与其他实现不一致,但Java的UUID.compareTo()
方法必须保持一致。 compareTo()
函数主要用于排序,UUID的排序顺序必须在Java版本之间保持稳定。
有符号比较
根本问题在于Java的long
类型是有符号类型,但来自RFC 4122的参考实现和其他工具和语言中的实现使用无符号类型进行计算。
由于数字溢出/下溢点不同,结果的排序略有不同。例如,Long.MAX_NUMBER
大于LONG.MAX_NUMBER + 1
,但对于它们的无符号对应物则不然。
Java实现的问题被发现得太晚,现在我们必须接受这种不兼容性。
实现附录
这里是RFC 4122的正确参考实现:
#define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
int uuid_compare(uuid_t *u1, uuid_t *u2)
{
int i;
CHECK(u1->time_low, u2->time_low);
CHECK(u1->time_mid, u2->time_mid);
CHECK(u1->time_hi_and_version, u2->time_hi_and_version);
CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved);
CHECK(u1->clock_seq_low, u2->clock_seq_low)
for (i = 0; i < 6; i++) {
if (u1->node[i] < u2->node[i])
return -1;
if (u1->node[i] > u2->node[i])
return 1;
}
return 0;
}
#undef CHECK
定义在结构体上
typedef struct {
unsigned32 time_low;
unsigned16 time_mid;
unsigned16 time_hi_and_version;
unsigned8 clock_seq_hi_and_reserved;
unsigned8 clock_seq_low;
byte node[6];
} uuid_t;
如您所见,他们逐个比较节点(按正确顺序),这些节点是byte
。
而Java的实现方式则是:
@Override
public int compareTo(UUID val) {
return (this.mostSigBits < val.mostSigBits ? -1 :
(this.mostSigBits > val.mostSigBits ? 1 :
(this.leastSigBits < val.leastSigBits ? -1 :
(this.leastSigBits > val.leastSigBits ? 1 :
0))));
}
基于两个(有符号)长整型:
private final long mostSigBits;
private final long leastSigBits;