提问者:小点点

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


我知道这个问题已经问过很多次了,但是我找不到我的问题的确切答案。

在有效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,仅仅是因为它们的hashcode没有被覆盖以返回相等对象的相等值(因为它将在另一个桶中搜索对象,因为不同的hashcode)。

但是根据我的理解,在那种情况下,不能保证两个对象的hashcode总是返回不同的。如果它们碰巧返回相同的hashcode呢?

我想这部分已经解释过了

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

我只是不明白缓存的事情。有人能详细解释一下吗?

还有,我已经做了家庭作业,发现了一个相关的问题

缓存与其get方法的每个条目关联的哈希码的HashMap优化的影响

但是我对接受的答案不太满意,回答者在评论中说

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

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


共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。哈希表是一个条目数组:

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

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

匿名用户

当说“即使两个实例碰巧散列到同一个桶”时,这并不意味着它们具有相同的哈希码。即使是不同的哈希码也可以映射到同一个桶[阅读关于哈希]。

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