给定以下密钥:
int key = Guid.NewGuid().GetHashCode();
这个键和Guid的唯一性一样吗?
int
有32位的信息。(编辑:为了澄清由于评论,据我所知,.NET GUID将允许任意设置这128位;随机生成的GUID遵循更严格的模式,因此不会生成2128个不同的值。尽管如此,仍然比232多。)GetHashCode()
从来不意味着表示唯一性。如果它可以,则很好-但即使有足够的int
值可用于此,它也不必这样做。
int.GetHashCode()
返回(例如)除以二的值将完全有效...因此,-1、0和1都将获得哈希码0;3和4将获得哈希码2等。这不是好的(而且比只返回值要慢),但它是一个有效的实现。它将满足GetHashCode
的所有约束-即,如果您在两个相等的值上调用它,它将返回相同的哈希码。今天我注意到了 Guid.GetHashCode()
的另一个问题:在微软.NET实现中,Guid
的并非每个“字节”都被哈希处理:有6个字节的Guid
没有被哈希,因此对其中任何一个字节的更改都不会改变哈希码。
我们可以在参考来源中看到此情况:
return _a ^ (((int)_b << 16) | (int)(ushort)_c) ^ (((int)_f << 24) | _k);
所以_d
, _e
, _g
, _h
, _i
, _j
字节不会被哈希。这对于"连续"的Guid
有重要影响,例如:
c482fbe1-9f16-4ae9-a05c-383478ec9d13
c482fbe1-9f16-4ae9-a05c-383478ec9d14
c482fbe1-9f16-4ae9-a05c-383478ec9d15
...
c482fbe1-9f16-4ae9-a05c-383478ec9dff
c482fbe1-9f16-4ae9-a05c-383478ec9e00
c482fbe1-9f16-4ae9-a05c-383478ec9e01
像这样的 Guid
,生成的不同哈希值数量非常小(256个不同的值),因为 3478ec9d
/3478ec9e
不会被哈希。
GetHashCode()
中包含的字段是60位时间戳和MAC地址的部分。对于版本4 UUID(从Guid.NewGuid()
获得),GUID的几乎所有字节都是随机的。因此,在这些情况下,算法似乎是可以接受的。 - Martin LiversageGetHashCode()
返回一个整数 - 它不能像Guid
那样唯一,因此不会保证唯一性并可能会发生碰撞。
散列码的关键是它应该在哈希范围内均匀分布,以便碰撞应该通常很少,但您始终有碰撞的机会,必须为此做出调整。
我在另一个答案中遇到了xanatos描述的问题。 我有一个类,其中使用两个Guid
值来区分不同的对象,我发现我的Guids产生了可怕的碰撞(我的Guids不是随机生成的)。 这是我用来解决问题的代码。 Guid1
和Guid2
是用于区分对象的Guid
类型属性。 该代码遵循Jon Skeet在此处描述的方法。
public override int GetHashCode()
{
int hash = 173;
foreach (Byte b in Guid1.ToByteArray().Concat(Guid2.ToByteArray()))
{
hash = hash * 983 + b;
}
return hash;
}
Guid是一个128位的数字。而int是32位的数字,所以它不能像Guid一样“唯一”。
此外,GetHashCode返回...哈希码,并不意味着它在任何方面都是唯一的。请参阅其他关于为什么存在GetHashCode()的SO讨论。
Guid
构造函数。你有任何相反的证据吗? - Jon SkeetGuid
类型,我仍然坚持认为该类型有2^128个可能的值。 - Jon SkeetGetHashCode
有什么用呢? 它不能可靠地用于确认2个事物是相同的或者不同的! - Jez