Java HashMap 键散列

Java HashMap key hashing

如果我在 hashmap 中输入一个键和值,根据键 hashcode 生成的索引大于 15,而映射大小仍然小于阈值 12,会发生什么情况?

提前致谢。

HashMap 通常会对 hashCode() 方法提供的值执行模运算,以便将整个范围的整数映射到其内部数组上的有效索引范围。

这可能会导致冲突(不同的哈希值映射到相同的索引),这是一个单独的主题,并且还会导致 HashMap 的 O(1) 预期时间退化。需要注意的是,假设您的 hashCode() 实现是均匀分布的。

在好的 HashMap API 中,您无需担心内部数组大小或冲突。这是由实现以各种方式在内部处理的。

Java 的 HashMap API 中没有公开可见的“阈值”。您可以获得的最接近的是:

HashMap(int initialCapacity, float loadFactor)

这里你说的threshold相当于loadFactor。根据 Java 文档:

“作为一般规则,默认加载因子 (.75) 在时间和 space 成本之间提供了一个很好的权衡。较高的值会减少 space 开销,但会增加查找成本(反映在HashMap的大部分操作中class,包括get和put)。在设置其初始容量时,应考虑映射中预期的条目数及其负载因子,以尽量减少映射的数量rehash 操作。如果初始容量大于最大条目数除以负载因子,则不会发生 rehash 操作。"

基本上这意味着如果 HashMap 中有太多冲突,它将扩展其当前数组大小并重新散列所有当前键,从而(希望)实现更均匀的分布。这应该具有预期的 O(1) 复杂度在 HashMap 的一系列添加或删除中保持的效果。

让我给你一个更广泛的画面,而不是只关注 Java 的特定数据类型 HashMap,因为你的问题包括 hashcode 标签,而且它似乎我,你对更通用的图片感兴趣 - 散列函数如何工作。

索引规范化

是你需要了解的。

一般来说,索引规范化如何发生完全取决于对键的输入进行哈希处理的特定数据结构的实现(如 HashTable/HashMap),无论它是什么实现,都可以肯定地说:

your hash function h(x) should be responsible for always and consistently producing an integer, which is in a valid index range of the backing array.

在许多实现中,散列函数可能 return 相当长(也可能是负数)的整数,这通常由 索引规范化 解决,它只是对那个长整数做一些事情(裁剪,使负数变为正数等)。

对于Java的HashMap实现,hashCode()是:

@HotSpotIntrinsicCandidate
public native int hashCode();

这意味着,该实现被委托给底层。

但在大多数情况下,您可以假设它将使用后备数组长度(桶数)的模数,这意味着它永远不会超过该数组的长度(因此,您的哈希图)。