为什么java.util.HashMap中的支持表索引对于两个不同的提供键是相同的?

时间:2013-07-23 07:20:21

标签: java collections hashmap hashcode

内部HashMap具有方法 hash(),它通过应用特殊函数来防止编写糟糕的哈希代码。 下一步是通过 hash()方法返回的值用于计算新条目存储在名为 table 的后备数组中的索引。 可能会发生 index 对于两个不同的键是相同的。因为使用了链接列表,但我很清楚。

为什么两个不同的密钥的支持表索引相同?

我知道哈希代码可能很难被覆盖,但方法 hash()表明它可以防止哈希代码冲突。那么为什么支持表的索引可以相同呢?

编辑感谢大家的回复。当您放入HashMap( size )的元素数量大于或等于阈值(根据构造函数中提供的initialCapacity和loadFactor计算)时,@ Dunkan Jones会自动调整大小。查看方法createEntry - 只要创建新Entry, size 就会递增。 我的问题是为什么hash()方法+ indexFor()方法为不同的对象返回相同的索引。由于这个相同的索引,两个条目通过链表放在同一个桶中。

什么原因导致hash()+ indexFor()方法返回相同的索引?

我认为并且无法通过那些棘手的>>>来实现hash()和indexFor()所做的事情。和&经营者?

HashMap中的哈希是什么意思?

再次感谢!

2 个答案:

答案 0 :(得分:1)

您是对的,内部hash()方法用于提高hashCode()结果的质量。内部Javadocs描述了原因:

  

检索对象哈希码并将补充哈希函数应用于    结果哈希,防御质量差的哈希函数。这是   因为HashMap使用两个幂的长度哈希表,所以很关键    否则会遇到没有差异的hashCodes的冲突    低位。注意:空键始终映射到散列0,因此索引为0。

但是,您的基本问题似乎是:为什么哈希映射允许多个值位于同一个“存储桶”中,而不仅仅是扩展地图的大小?

答案将是表现。在调整大小操作期间重新计算地图中的所有哈希值很昂贵。在某一点上,将多个值填充到同一个桶中会更便宜。

答案 1 :(得分:1)

如果我没记错的话,每个可以作为哈希映射键的对象都应该覆盖hashCode()方法,所以一般契约(来自Javadoc)是

  

如果两个对象根据equals(Object)方法相等,则在两个对象中的每一个上调用hashCode方法必须产生相同的整数结果。

换句话说:

  

o1.equals(o2)然后o1.hashCode() == o2.hashCode()

哈希映射在内部使用另一个hash()函数,该函数从hashCode()值创建另一个哈希码。此函数在某些时候使用模数(对于空间效率),因此不同的hashCode()值可以等于hash()值(键与hash()值映射)。

这不是问题,因为如果地图中的两个键具有等于hash()值,则在搜索时将与equals()方法进行比较,以确保它们具有相同的键,并且没有两个对象巧合的是,它具有相同的哈希码。

一些资源:

OP编辑后编辑

我认为indexFor计算模数。功能是

static int  indexFor(int h, int length) {
   return h & (length-1);
}

我们知道(来自theorya % b == a & (b - 1) iff b 是2 n 。长度字段(我们的“ b ”)是2 n 的倍数:

  

将补充哈希函数应用于给定的hashCode,以防御质量差的哈希函数。这很关键,因为HashMap使用两个幂的长度哈希表,否则会遇到低位不同的hashCodes的冲突。注意:空键始终映射到散列0,因此索引为0。

因此不同的哈希值可以具有相同的模数,因此不同的对象可以具有相同的索引。