HashCode - 如果相同的对象碰巧在同一个桶中散列会发生什么?

时间:2013-04-19 03:40:46

标签: java hashcode language-lawyer

我知道这已被多次询问,但我无法找到问题的确切答案。

在Effective Java的第3章中,有一个场景显示和解释了为什么hashcode应该与equals方法一起覆盖。我得到了大部分内容,但有一部分我无法理解。

有一个给定的类覆盖equals方法但不覆盖hashCode方法。该对象作为地图中的键

Map<PhoneNumber, String> m = new HashMap<PhoneNumber, String>();
m.put(new PhoneNumber(707, 867, 5309), "Jenny");

我理解如果我们get使用另一个相等的对象(m.get(new PhoneNumber(707, 867, 5309))),它将返回null,因为它们的哈希码不会被覆盖以返回相等对象的相等值(因为它将搜索因为不同的哈希码而在另一个桶中的对象)。

但根据我的理解,在这种情况下,无法保证两个对象的哈希码总是会返回不同的。如果他们碰巧返回相同的哈希码怎么办?

我认为这部分已经解释了

  

即使两个实例碰巧哈希到同一个桶,也就是get   方法几乎肯定会返回null,因为HashMap有一个   缓存与每个条目相关联的哈希码的优化   如果哈希码没有,则不会检查对象是否相等   匹配。

我只是没有得到缓存的东西。有人可以精心解释这个吗?

另外,我已经完成了自己的家庭工作,并找到了一个相关的问题

Influence of HashMap optimization that caches the hash code associated with each entry to its get method

但我对接受的答案并不满意,回答者在评论中表示

  

哈希码可以是任意int,因此每个哈希码都不能   自己的水桶。因此,一些对象具有不同的哈希码   最终在同一个桶里。

我完全不同意。据我所知,不同的哈希码永远不会在同一个桶中结束。

2 个答案:

答案 0 :(得分:2)

看看java.util.HashMap如何通过hashCode计算密钥的桶号:

/**
 * Returns index for hash code h.
 */
static int indexFor(int h, int length) {
    return h & (length-1);
}

如果散列表长度= 16,则128和256都将进入#0桶。 Hashtable是一系列条目:

   Entry<K,V>[] table
   ...
   class Entry<K,V> {
           K key;
           V value;
           Entry<K,V> next;
           int hash;
    ...

条目可以形成一个链(LinkedList)。如果存储桶#0(table[0])为空(null),则新条目将直接放在那里,否则HashMap将找到链中的最后一个条目并设置最后一个条目的next = new条目。

答案 1 :(得分:0)

当说“即使两个实例碰巧哈希到同一个桶”时,并不意味着它们具有相同的哈希码。甚至不同的哈希码也可以映射到同一个桶[读取哈希值]。

因此,即使密钥散列到同一个桶,也可能不会为相关元素调用.equals(由于缓存优化)(因为即使哈希代码也不匹配)。因此,即使相关元素驻留在同一个桶中,也可能永远不会通过.equals进行比较,因此不会“找到”。