Java 为什么要在HashMap中使用hash方法

Java 为什么要在HashMap中使用hash方法,java,hashmap,Java,Hashmap,hash方法状态的Java文档 检索对象哈希代码,并对结果哈希应用补充哈希函数,以防止质量差的哈希函数。这是至关重要的,因为HashMap使用两个长度哈希表的幂,否则会遇到低位不不同的哈希代码冲突 我不能理解的是 1) 为什么HashMap使用两个长度哈希表的幂 声明表时也会说明: /** * The table, resized as necessary. Length MUST Always be a power of two. */ transient Entry<K,V>

hash
方法状态的Java文档

检索对象哈希代码,并对结果哈希应用补充哈希函数,以防止质量差的哈希函数。这是至关重要的,因为HashMap使用两个长度哈希表的幂,否则会遇到低位不不同的哈希代码冲突

我不能理解的是

1) 为什么HashMap使用两个长度哈希表的幂

声明表时也会说明:

/**
 * The table, resized as necessary. Length MUST Always be a power of two.
 */
transient Entry<K,V>[] table;
/**
*表,根据需要调整大小。长度必须始终是2的幂。
*/
瞬态条目[]表;
为什么会有这种限制


2) 否则,对于低位没有差异的哈希代码,会遇到什么冲突。意味着什么?

当哈希映射需要调整大小时,会创建一个新的存储桶数组,使用
hashCode()访问这些存储桶。
(通过少量附加操作将
int
hashCode映射到hashMap中的存储桶数)。

这个数组的2倍大小允许将
int
hashCode巧妙地映射到bucket number——基本上只使用hashCode的下半部分(屏蔽上半部分)来寻址bucket。

hashmap的目的是非常快地缩小需要查看的对象数量(理想情况下为0或1)搜索特定密钥时

HashMap.get(key)
的一般方法如下:

  • 调用
    key.hashCode()
    以获取表示对象的单个整数

  • 查看基于该哈希代码的哈希“bucket”,它可以包含零个或多个条目

  • 检查bucket中的每个条目,找出是否有条目的key是
    。equals(key)
    。如果是,则返回它。如果bucket中没有条目的key与搜索的条目相同,则返回null

  • 好的hashmap和坏的hashmap的区别在于速度。您必须平衡这三个方面:

  • 您能以多快的速度将密钥转换为哈希代码

  • 两个不同的键映射到同一哈希代码的频率是多少

  • 您多久会将两个具有不同哈希代码的键放入同一个“bucket”中

  • Java的设计人员选择了一组他们认为最好的折衷方案。没有正确的答案,但您必须选择一种特定的方法,并将该方法写入文档中

    Java的设计者可能有一些基于添加到hashmaps中的典型数据的统计证据

    他们选择通过提取哈希代码的最低n位来将哈希代码转换为bucket,因为这些位的变化比最高的位更频繁。他们选择提取位,而不是将哈希代码转换为bucket的另一种典型方法(除以素数后的整数余数)因为在Java最常用的部署平台上,它通常是一种更快的操作

    Java的设计人员可能已经发现,步骤1,即
    hashCode()
    的实现,是由Java用户编写的,通常会很糟糕,因为对于他们想要存储在同一个hashmap中的许多对象返回相同的hashCode。想象一下,如果hashCode是这样的:

    public class MyInteger {
        final int i;
        public MyInteger(int i) {
            this.i = i;
        }
        public int hashCode() {
            return i << 24; // will return 0x00000000, 0x01000000, etc.
        }
        public boolean equals(Object o) {
            return (o != null) && (o instanceof MyInteger) && ((MyInteger)o).i == i;
        }
    }
    
    公共类MyInteger{
    最终int i;
    公共MyInteger(整数i){
    这个。i=i;
    }
    公共int hashCode(){
    
    return我请在一篇文章中问一个具体的问题。这个问题已经在这篇文章中讨论过了:它使用两个大小的幂,因为你可以通过
    hashCode&MASK
    where
    MASK=000….111
    where amount of 1s==当前用于大小的幂2来轻松地选择桶。这没有回答任何问题。它可以使用其他growth函数。“一些巧妙的映射”并不是一个严肃的解释。@Andrey它为OP和未来读者的进一步研究留下了一些空间。我可以更具体地说,“巧妙的映射”基本上只使用哈希代码的较低部分(屏蔽较高部分)来处理桶。