`
helloworldfengyun
  • 浏览: 14018 次
  • 性别: Icon_minigender_1
  • 来自: 山西
社区版块
存档分类
最新评论

Java HashMap的hash和indexFor函数

阅读更多

        此文章,我们将一起了解一下hash和indexFor方法在hashmap内部起什么作用。hash和indexFor方法属于HashMap类,为什么JDK开发者在key对象已经有他自己的hashcode方法的情况下还需要另一个hash函数?

        首先看一下hash和indexFor方法的代码:

        

/**
     * Applies a supplemental hash function to a given hashCode, which
     * defends against poor quality hash functions.  This is critical
     * because HashMap uses power-of-two length hash tables, that
     * otherwise encounter collisions for hashCodes that do not differ
     * in lower bits. Note: Null keys always map to hash 0, thus index 0.
     */
    static int hash(int h) {
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    /**
     * Returns index for hash code h.
     */
    static int indexFor(int h, int length) {
        return h & (length-1);
    }

      正如java doc对hash方法的描述:将hash函数作为已给定的hashCode的一个补充,可以提高hash函数的质量。hash质量的好坏是非常重要的,因为HashMap用2的次幂作为表的hash长度,这就容易产生冲突,因为hashCodes在低位不是不同的(hashCodes that do not differ in lower bits)。注意:Null 的key的hash值总是0,即他在table的索引为0。

       让我们通过例子来帮助我们理解一下上面的话。加入说key object的hashCode()只返回三个值:31、63和95.31、63和95都是int型,所以是32位的。

        31=00000000000000000000000000011111
        63=00000000000000000000000000111111
        95=00000000000000000000000001011111

      现在加入HashMap的table长为默认值16(2^4,HashMap的长度总是2的次幂)

      假如我们不用hash函数,indexFor将返回如下值:

      31=00000000000000000000000000011111 => 1111=15
      63=00000000000000000000000000111111  => 1111=15
      95=00000000000000000000000001011111 => 1111=15

为什么会这样?因为当我们调用indexFor函数的时候,它将执行31&15,,63&15和95&15的与操作,比如说95&15得出一下结果:

        00000000000000000000000001011111 &00000000000000000000000000001111

        也就是说(2^n-1)总会是一个1的序列,因此不管怎样,最后会执行0&1的于然后得出0.

        上面的例子,也就解释了凡是在末尾全是1111的都返回相同的index,因此,尽管我们有不同的hashcode,Entry对象却讲都被存在table中index为15的位置。

        倘若我们使用了hash函数,对于上面每一个hashcode,经过hash作用作用后如下:

        31=00000000000000000000000000011111 => 00000000000000000000000000011110
        63=00000000000000000000000000111111  => 00000000000000000000000000111100
        95=00000000000000000000000001011111 => 00000000000000000000000001011010

        现在在通过新的hash之后再使用indexFor将会返回:

        00000000000000000000000000011110 =>1110=14
        00000000000000000000000000111100 =>1100=12
        00000000000000000000000001011010 =>1010=10

        在使用了hash函数之后,上面的hashcodes就返回了不同的index,因此,hash函数对hashmap里的元素进行了再分配,也就减少了冲突同时提高了性能。

         hash操作最主要的目的就是在最显著位的hashcode的差异可见,以致于hashmap的元素能够均匀的分布在整个桶里。

         有两点需要注意:

          如果两个key有相同的hashcode,那他们将被分配到table数组的相同index上

           如果两个key不具有相同的hashcode,那么他们或许可能,或许也不可能被分配到table数组相同的index上。

         英文参考文档:http://javapostsforlearning.blogspot.in/2014/02/hash-and-indexfor-method-in-hashmap.html

 

分享到:
评论

相关推荐

    java中HashMap详解.pdf

    为了找到对应的数组位置,HashMap使用了indexFor()方法,该方法通过将散列值与数组长度减一进行按位与操作来得到索引值: ```java static int indexFor(int hash, int length) { return hash & (length - 1); } ``...

    全排列的Hash函数(JAVA)

    标题中的“全排列的Hash函数(JAVA)”指的是在Java编程中使用Hash函数处理全排列问题。全排列是指从n个不同元素中取出m个元素,按照一定的顺序排列起来的所有可能的排列方式。在这个场景下,Hash函数通常用于快速查找...

    Hashmap详解

    HashMap 是一种常用的数据结构,在 Java 中,它是一个数组和链表的结合体。下面我们将深入探讨 HashMap 的数据结构、 put 方法的实现细节和 Hash 码的计算过程。 HashMap 的数据结构 HashMap 的数据结构可以分为两...

    HashMap介绍和使用

    static int indexFor(int h, int length) { return h & (length - 1); } ``` 这里的`length`是指数组的长度,必须是2的幂。例如,数组长度为16时,`length - 1`等于15,即二进制表示为`1111`。哈希值与`1111`进行...

    HashMap的数据结构

    Java中的HashMap使用`hashCode()`方法来计算键的哈希码,并通过`indexFor(int h, int length)`方法将其映射到数组的合适位置。哈希函数的设计至关重要,因为它直接影响到HashMap的性能。 2. **装载因子**:装载因子...

    深入解析java HashMap实现原理

    存储元素时,首先通过`hash(key.hashCode())`计算哈希值,然后使用`indexFor(hash, table.length)`确定元素在数组中的位置。如果两个键的哈希值相同,它们会在同一个数组索引处形成链表。哈希函数设计的目标是使得...

    HashMap的实现原理

    2. **确定数组索引**:使用 `indexFor(hash, table.length)` 方法来计算出该键值对应该存储在数组中的具体位置。 3. **检查链表**:如果该位置已经有元素存在,则遍历该位置的链表,检查是否已有相同的键存在。 - ...

    一个基于js的HashMap

    在JavaScript中,HashMap是一种数据结构,它允许我们通过键(key)来存储和检索值(value),类似于对象,但提供了一种更高效的方式来处理大量数据。JavaScript原生并不支持HashMap,但开发者可以通过自定义类来实现...

    hashmap.zip

    在实际应用中,应使用Java内置的HashMap类,因为它提供了更高效、完善的实现和功能。 在理解HashMap的工作原理后,可以更好地优化和利用它。例如,通过重写键的hashCode()方法来减少哈希冲突,或者在设计键时避免...

    Java容器HashMap与HashTable详解

    当插入元素时,HashMap会计算key的hashCode,通过hash()函数转化为一个哈希值,再通过indexFor()函数确定在数组中的索引位置。如果该位置已有元素,新元素将被添加到链表中。在获取值时,HashMap同样根据key的...

    HashMap专题讲解

    接着,`hash`方法计算键值对象的哈希码,然后`indexFor`函数将哈希码转换为数组索引。在存储过程中,HashMap可能会遇到哈希冲突,此时它会遍历冲突位置上的链表,找到匹配的键值对进行替换或插入新元素。如果不存在...

    (001)HashMap之链表转红黑树-treefyBin方法.docx

    在Java的集合框架中,HashMap是一种高效的键值对存储结构,它通过散列函数实现快速查找。当元素数量增加,导致某一个桶(bucket)内的链表过长时,为了保持查询性能,HashMap会将链表转换为红黑树。这个过程主要由`...

    hashmap_use_in_JDK7.zip

    2. **哈希函数**:HashMap通过键对象的`hashCode()`方法计算哈希值,然后使用`indexFor(int hash, int length)`方法确定元素在数组中的位置。这个过程是为了尽量使不同的键分散在数组的不同位置,减少哈希冲突。 3....

    深入理解Java中的HashMap的实现机制

    数组长度为2的幂,意味着哈希值可以通过位运算快速映射到数组索引,例如`indexFor(hash, table.length)`。 总的来说,HashMap通过高效的哈希函数和冲突解决策略提供了快速的插入、查找和删除操作。其性能通常接近O...

    java7hashmap源码-Java8_Advance:中级水平

    HashMap在Java 7中的核心实现基于数组和链表,它通过哈希函数将键(key)映射到数组的特定位置,以实现快速查找。当多个键哈希到同一个位置时,会形成一个链表,解决哈希冲突问题。下面我们将详细探讨HashMap的构造...

    Hash map implementation in C. .zip

    哈希表(Hash Map)是一种在编程中广泛使用的数据结构,它通过散列函数将键(Key)映射到一个数组的索引位置,从而实现快速查找、插入和删除操作。在C语言中,虽然没有内置的哈希表类型,但我们可以自定义一个哈希表...

    面试官!你又双叒叕问HashMap!

    Java的HashMap默认使用`Object`类的`hashCode()`方法获取键的哈希值,并通过`indexFor(int hash, int size)`方法计算桶的位置。 **初始化容量与2的倍数** HashMap在初始化时要求容量必须是2的幂,例如16、32等。这...

    sesvc.exe 阿萨德

    for (Entry,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null...

Global site tag (gtag.js) - Google Analytics