HashMap底层实现原理

大家都知道HashMap是存储key-value形式的集合,允许key和value为null。那么HashMap底层到底是如何实现的呢?今天查了一些资料,简单记录一下。
HashMap底层通过数组和链表实现。数组可以理解,那么链表是用来做什么的呢?这是因为两个不同的对象,hashCode是可能相等的。为了在数组存储hashCode相等的两个不同对象,实际上,一个数组里面的元素,是一个链表。当根据hashCode,得到数组的索引时,先去数组中该处是否已经有值,如果有,再去判断两个对象是否相等,如果相等,则替换旧值,如果不等,则在链表尾部添加元素。
看一下HashMap的put方法:

public V put(K key, V value) {  
    // HashMap允许存放null键和null值。  
    // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。  
    if (key == null)  
        return putForNullKey(value);  
    // 根据key的keyCode重新计算hash值。  
    int hash = hash(key.hashCode());  
    // 搜索指定hash值在对应table中的索引。  
    int i = indexFor(hash, table.length);  
    // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。  
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
        Object k;  
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
            V oldValue = e.value;  
            e.value = value;  
            e.recordAccess(this);  
            return oldValue;  
        }  
    }  
    // 如果i索引处的Entry为null,表明此处还没有Entry。  
    modCount++;  
    // 将key、value添加到i索引处。  
    addEntry(hash, key, value, i);  
    return null;  
}  

通过上面方法可以清楚的看出,当遇到hashCode相等的情况时,是如何处理的。
仔细看一下代码,我们发现,数组索引的位置并不是直接通过hashCode得到的,而是先调用了hash()方法,从新计算hash值,然后再通过indexFor()方法计算,才最终得到数组的索引。为什么不直接使用hashCode呢?带着这个疑问,我们依次看看上面两个方法:

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

先看indexFor方法,它对length-1进行了与操作,当length总是 2 的n次方时,h& (length-1)运算等价于对length取模,也就是h%length,但是&比%具有更高的效率。而HashMap底层数组的长度总是 2 的 n 次方,这是HashMap在速度上的优化。
按道理讲,这样就可以了得到索引了,为何还要下面的hash方法呢?先看看hash()方法的作用是什么

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

可以看出,它是对hashCode的高16位和低16位做了一个异或操作。这样就相当于,我们在执行indexFor()方法时,引入了高16位的数据,减少了hash碰撞的可能性。从而get请求查询需要遍历链表的情况表少,查询操作更快。

引用:http://www.importnew.com/18633.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值