Java8 HashMap源码分析

前言

      今天,我们主要来研究一下在Java8中HashMap的数据结构及一些重要方法的具体实现。
      研究HashMap的源代码之前,我们首先来研究一下常用的三种数据结构:数组、链表和红黑树。
      数组作为一种基本的数据结构,以线性的方式组织数据,按数据的插入顺序来排列数据。在内存中,数组的物理组织形式是一段连续的内存空间。在数据操作上,由于数组的物理特点,可以在O(1)的时间复杂度内完成数据的查找,在插入和删除上需要更长的时间(O(n)的时间复杂度)。
      链表在逻辑特性上基本与数组保持一致,同样以线性的方式组织数据,按数据的插入顺序来排列数据。在内存中,链表的物理组织形式是离散的磁盘空间,通过指针进行不同链表节点的链接,因此在数据的插入和删除上具有非常好的性能,可以达到O(1)的时间复杂度,但是在查找上面性能较差,需要O(n)的时间复杂度。
      红黑树是一种经过了优化的平衡二叉树,可以在数据的插入上获得更好的性能。首先红黑树在数据的查找上可以达到O(nlog(n))的时间复杂度,同时数据的插入和删除,可以实现局部调整,从而可以承担更少的性能代价(相较于平衡二叉树)。
      HashMap的设计就是为了在查找上获得最优的性能(希望基本获取O(1)的时间复杂度),因此HashMap主要使用了数组作为核心的数据存储的结构,同时使用链地址法解决K-V映射时产生的碰撞,在Java8中同时加入了红黑树来优化碰撞时数据匹配的性能。HashMap的组织形式大致如下图所示:

HashMap的映射方法

      Java8中结合元素自身的hashcode以及再hash的方式来获取元素的哈希值,在通过取模的方式映射到数组中,其中取模运算是通过优化后的位运算来实现的。首先来看一下元素的hashcode的获取方法:

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

      由此可知,HashMap是使用元素自身的hashcode的前16位作为哈希值的。结下来看一看如何使用该哈希值做映射,为了说明方便我们使用Java7中的indexFor函数来做说明,在Java8中虽然没有显示的这个函数了,但该函数的具体实现被嵌入到了具体的各个方法中了。

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

      如上,需要解释两个问题,1)如何使用位运算&来实现取模运算2)在HashMap中,数组table的长度为啥必须为2的n次方。

      首先来解释第一个问题1)如何使用位运算&来实现取模运算。先来看一个简单的例子,当数组的长度为16的时候,实现取模运算和位运算&时候的结果如下:

key&(table.length-1)         二进制 index key%(table.length-1) index
4&15                                100&1111 100 4%15 4
13&15                              1101&1111 1101 13%15 13
19&15                              10011&1111 11 19%15

4

      由上表可知,可以通过位运算&的方式,实现hashcode的映射,将不同的hashcode映射到不同的数组下标中,并且如表所知,可以通过hashcode的末几位决定映射后的下标位置。同时可以知道,实际上hashcode的很多位是用不上的,因此在HashMap的hash函数中,才使用了移位运算,只取了hashcode的前16位来做映射。
      同时另一方面,虽然通过对2^n-1做&运算不会和%运算获得同样的结果,但是能够将hashcode做一个均匀的散列,其效果完全等同于取模运算,并且会有更优的运算性能。
      因此第二个问题2)HashMap中,数组table的长度为啥必须为2的n次方的第一个层面就回答完了,为了在&运算中,使元素在数组中映射的更均匀,达到%运算的效果,所以将数组的大小必须设定位2的n次幂。同时该大小的设定还有第二个层次的原因,具体我们将在resize函数的解析中,做进一步的剖析,请继续研读下去。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值