System.identityHashCode 方法返回的哈希码是否唯一分配给每个对象?
Are the hashcodes returned by the System.identityHashCode method uniquely assigned to each object?
System.identityHashCode 方法返回的哈希码是否唯一分配给每个对象?
由于hashcode是一个int,因此可能的值是4,294,967,295,那么jvm是否保证在如此多的对象中每个对象至少有一个唯一的hashcode?
不,这并非对所有对象都是唯一的。这完全取决于您的 JVM 实现。您只能确定对于同一个对象此方法 returns 相同的值。
根据我的阅读,而不是为 object 的身份哈希码保留 space,至少某些版本的 JVM 在 object 中保留了几个位的 header 表示应用了三个条件中的哪一个:
- 尚未检查身份哈希码。
- 身份哈希码已经过检查,object从那时起就没有被移动过。
- 检查了身份哈希码,然后移动了 object。
当 object 处于状态 #1 时获取身份 hashCode 会将其更改为状态 #2 并且 return 一个从 object 的地址派生的值。当 object 处于状态 #2 时获取身份 hashCode 将简单地对地址执行相同的计算。
如果处于状态 #1 的 object 需要重新定位,它将只停留在状态 #1。如果 object 在处于状态 #2 时被重新定位,系统将制作一个副本,其中有额外的四个字节保留用于哈希码,根据旧地址计算哈希码,并将其存储在保留的那些字节,并将 object 标记为处于状态 #3。之后,任何读取哈希码的尝试都会报告保存的值。
如果一个 object 被创建,然后被重新定位或销毁,它之前占据的 space 可能会在未来的某个时间被用来容纳一个新的 object。这样的 object 很可能与旧地址具有相同的地址;如果匹配,则身份哈希码可能会匹配。
请注意,预计 hashCode 函数不足以避免所有冲突,而只是足以将大量比较变成少量比较。如果哈希码可以将比较次数从 10,000 次减少到 10 次,那比将比较次数从 10 次减少到 1 次要大得多。
鸽巢原则适用。
如果你有4个鸽子洞,5只鸽子都必须找到一个鸽子洞栖息,那么至少有一个鸽子洞里会有不止一只鸽子。
很明显,对吧?
同样适用于此。只有2^32
个不同的鸽子洞哈希码(因为值是一个int
,java中的int定义为32位数字,因此,只有 2^32 个不同的可能值存在)。这是一个很大很大的数字。约40亿。
但是,java 规范中没有任何内容规定永远不能存在超过 40 亿个 pigeons 个对象。如果存在超过 40 亿个对象,那么由于这一原则,任何人可能设计的算法都不能保证唯一性。 QED.
NB:你也可以用鸽巢原理证明万能压缩器(一种可以压缩任何东西的工具,保证压缩后的结果总是小于或等于)是不存在的,只要它真正压缩任何东西,那么结果必然是一些比特流,压缩器实际上会为这些比特流生成一个 更大的 文件。您可以使用它来证明 (int) (Math.random() * 10)
不是完全均匀随机的,以及为什么您应该使用 random.nextInt(10)
代替(这是)。在计算机科学中证明事物是一个非常有用的原则!
现在,人们可以想象一个基于 int
的编码系统,它承诺提供唯一代码 直到 你遇到 40 亿个唯一对象,但是做出这样的承诺非常复杂并且如果它必须为任何和所有对象工作,它本身就是一个内存消耗者。
Java 没有做出这样的承诺,因此 System.iHC
不能保证拥有唯一的数字(完全不可能做出这样的承诺),也不保证 System.iHC
有 'perfect' 分布(散列码尽可能地分布,即在同时存在 40 亿个对象之前不会重用)。请注意 'exists' 已经很复杂了:什么时候对象真正 'disappear'?
实际上,iHC 是基于记忆位置的;它的分布非常非常好。但是,任何 2 个对象都不太可能具有相同的身份哈希码和我们保证没有两个对象共享身份哈希码之间存在差异].
System.identityHashCode 方法返回的哈希码是否唯一分配给每个对象?
由于hashcode是一个int,因此可能的值是4,294,967,295,那么jvm是否保证在如此多的对象中每个对象至少有一个唯一的hashcode?
不,这并非对所有对象都是唯一的。这完全取决于您的 JVM 实现。您只能确定对于同一个对象此方法 returns 相同的值。
根据我的阅读,而不是为 object 的身份哈希码保留 space,至少某些版本的 JVM 在 object 中保留了几个位的 header 表示应用了三个条件中的哪一个:
- 尚未检查身份哈希码。
- 身份哈希码已经过检查,object从那时起就没有被移动过。
- 检查了身份哈希码,然后移动了 object。
当 object 处于状态 #1 时获取身份 hashCode 会将其更改为状态 #2 并且 return 一个从 object 的地址派生的值。当 object 处于状态 #2 时获取身份 hashCode 将简单地对地址执行相同的计算。
如果处于状态 #1 的 object 需要重新定位,它将只停留在状态 #1。如果 object 在处于状态 #2 时被重新定位,系统将制作一个副本,其中有额外的四个字节保留用于哈希码,根据旧地址计算哈希码,并将其存储在保留的那些字节,并将 object 标记为处于状态 #3。之后,任何读取哈希码的尝试都会报告保存的值。
如果一个 object 被创建,然后被重新定位或销毁,它之前占据的 space 可能会在未来的某个时间被用来容纳一个新的 object。这样的 object 很可能与旧地址具有相同的地址;如果匹配,则身份哈希码可能会匹配。
请注意,预计 hashCode 函数不足以避免所有冲突,而只是足以将大量比较变成少量比较。如果哈希码可以将比较次数从 10,000 次减少到 10 次,那比将比较次数从 10 次减少到 1 次要大得多。
鸽巢原则适用。
如果你有4个鸽子洞,5只鸽子都必须找到一个鸽子洞栖息,那么至少有一个鸽子洞里会有不止一只鸽子。
很明显,对吧?
同样适用于此。只有2^32
个不同的鸽子洞哈希码(因为值是一个int
,java中的int定义为32位数字,因此,只有 2^32 个不同的可能值存在)。这是一个很大很大的数字。约40亿。
但是,java 规范中没有任何内容规定永远不能存在超过 40 亿个 pigeons 个对象。如果存在超过 40 亿个对象,那么由于这一原则,任何人可能设计的算法都不能保证唯一性。 QED.
NB:你也可以用鸽巢原理证明万能压缩器(一种可以压缩任何东西的工具,保证压缩后的结果总是小于或等于)是不存在的,只要它真正压缩任何东西,那么结果必然是一些比特流,压缩器实际上会为这些比特流生成一个 更大的 文件。您可以使用它来证明 (int) (Math.random() * 10)
不是完全均匀随机的,以及为什么您应该使用 random.nextInt(10)
代替(这是)。在计算机科学中证明事物是一个非常有用的原则!
现在,人们可以想象一个基于 int
的编码系统,它承诺提供唯一代码 直到 你遇到 40 亿个唯一对象,但是做出这样的承诺非常复杂并且如果它必须为任何和所有对象工作,它本身就是一个内存消耗者。
Java 没有做出这样的承诺,因此 System.iHC
不能保证拥有唯一的数字(完全不可能做出这样的承诺),也不保证 System.iHC
有 'perfect' 分布(散列码尽可能地分布,即在同时存在 40 亿个对象之前不会重用)。请注意 'exists' 已经很复杂了:什么时候对象真正 'disappear'?
实际上,iHC 是基于记忆位置的;它的分布非常非常好。但是,任何 2 个对象都不太可能具有相同的身份哈希码和我们保证没有两个对象共享身份哈希码之间存在差异].