一尘不染

Java使用什么哈希函数来实现Hashtable类?

algorithm

在CLRS(“算法简介”)一书中,有几种哈希函数,例如mod,multiple等。

Java使用什么哈希函数将密钥映射到插槽?

我在这里看到Java语言中使用的哈希函数存在一个问题。但是它不能回答问题,我认为该问题的标记答案是错误的。它说hashCode()允许您为Hashtable做自己的哈希函数,但是我认为这是错误的。

hashCode()返回的整数是Hashtble的实键,然后Hashtable使用哈希函数对hashCode()进行哈希处理。这个答案的含义是Java给您提供了给Hashtable哈希函数的机会,但是不,这是错误的。hashCode()提供实键,而不是散列函数。

那么Java使用什么哈希函数呢?


阅读 198

收藏
2020-07-28

共1个答案

一尘不染

将密钥添加到OpenJDK中的HashMap或从中请求时,执行流程如下:

  1. 使用开发人员定义的hashCode()方法将密钥转换为32位值。
  2. 然后,通过 第二个哈希函数 (Andrew的答案包含源代码)将32位值转换为哈希表内部的偏移量。第二个哈希函数由HashMap的实现提供,并且不能被开发人员覆盖。
  3. 哈希表的相应条目包含对链表的引用;如果该键在哈希表中尚不存在,则为null。如果存在冲突(多个具有相同偏移量的键),则将键及其值简单地收集在一个单链表中。

如果将哈希表的大小选择为适当高,则冲突次数将受到限制。因此,单次查找平均只需要恒定的时间。这称为 预期恒定时间
。但是,如果攻击者可以控制插入到哈希表中的密钥并了解所使用的哈希算法,则他可能会引起很多哈希冲突,因此会强制执行线性查找时间。这就是为什么最近对某些哈希表实现进行了更改,以包括一个随机元素的原因,这使得攻击者更难预测哪些键将导致冲突。

一些ASCII艺术

key.hashCode()
     |
     | 32-bit value
     |                              hash table
     V                            +------------+    +----------------------+
HashMap.hash() --+                | reference  | -> | key1 | value1 | null |
                 |                |------------|    +----------------------+
                 | modulo size    | null       |
                 | = offset       |------------|    +---------------------+
                 +--------------> | reference  | -> | key2 | value2 | ref |
                                  |------------|    +---------------------+
                                  |    ....    |                       |
                                                      +----------------+
                                                      V
                                                    +----------------------+
                                                    | key3 | value3 | null |
                                                    +----------------------+
2020-07-28