随机整数作为 hashCode

Random integer as hashCode

在构造函数中生成一个随机数并从 hashCode 方法 return 这个值是个好主意吗? 有可能发生冲突,但这适用于编写您自己的 hashCode 方法。那么有什么缺点呢? 当在 HashMap 中使用此对象时,它将与随机数一起作为哈希存储,然后由相同的方法检索。如果有冲突,它们将由 equals.

解决

hashCode contract 指定

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

所以不,让它随机是个坏主意。

基本答案

在典型的用例中,您不希望使用用于将其插入到哈希集合中的相同(就身份而言)键对象进行检索,而是使用逻辑上等效的对象(就身份而言)等于)。

因此,您希望以下代码在地图中查找元素

Key k1 = new Key("param1", "param2");
Key k2 = new Key("param1", "param2");
Value val1 = new Value();

map.put(k1, value);

Value val2 = map.get(k2);

如果 hashCode 仅基于随机数,则 k1 和 k2 具有不同的哈希值,因此可能会指向 HashMap 的不同桶。

我们表明,对于实现 equals 的对象,随机 hashCode 不是一个好主意。 这是 hash code contract:

部分背后的原因

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

更高级的部分:

Let's take a look at Object.hashCode implementation。 请注意,identity hashCode() 实现依赖于 JVM。

查看 JDK 来源,get_next_hash 提供了六种计算 hashCode 的方法:

0. A randomly generated number.
1. A function of memory address of the object.
2. A hardcoded 1 (used for sensitivity testing.)
3. A sequence.
4. The memory address of the object, cast to int.
5. Thread state combined with xorshift (https://en.wikipedia.org/wiki/Xorshift)

OpenJDK 7和OpenJDK 6都使用第一种方法,随机数生成器。

OpenJDK 8 将默认值更改为 5 - 线程状态与 xorshift 相结合。

请注意,Object.hashCode 的所有这些实现都与 Object.equals 一致(在哈希码合同方面)

总而言之,您将实施 Object.hashCode 背后的策略之一,但如果实施 equals,则有违约的风险。

如果你什么都不做,使用Object.hashCode()(对象的“内存地址”),那么你或多或少已经达到了你想要的目的。因此,您可以拥有任何 class.

的 HashMap/HashSet 键

还有保险箱equals