java HashMap的实现原理

来源:互联网 发布:python画爱心 编辑:程序博客网 时间:2024/04/27 08:01

Java中的HashMap是根据Hash表(散列表)来实现的,

Hash表的模型

Hash表的一些概念。

 1> capacity是指hash表的长度,size是Hash表里面实际元素的个数,size/capacity 称为装填因子,用来表示关键字个数和表长度的比值。loadFactory是所能允许的最大的元素个数填满hash表的最大比例,也就是最大的装填因子。

threshold(Hash表里面所能容纳的最多元素的个数)= capacity * loadFactory.

put 函数的实现

1>首先依据hash函数根据key的hashCode值来计算hash值,找到该元素应该放置的位置。即Index = hash(key.hashCode())

2> 如果该index位置为空,即没有发生碰撞,则将节点(包括key,value)放在该位置上。函数结束

3> 如果碰撞了,则以链表形式存放在该位置的链表中。

4> 如果节点已经存在,那么用新的value值替换旧的value值。

5> 如果hash表的元素个数超过threshold,则resize  Hash表。

get函数的实现

1> 通过hash(key.hashCode())计算出该key的index值,然后去hash表里面找,然后根据key.equals(node.key)来判断是不是该节点,如果找到,就返回这个节点的value值

2> 否则就要去该位置对应的链表里面来查找。


 总结

我们现在可以回答开始的几个问题,加深对HashMap的理解:

1. 什么时候会使用HashMap?他有什么特点?
是基于Map接口的实现,存储键值对时,它可以接收null的键值,是非同步的,HashMap存储着Entry(hash, key, value, next)对象。

2. 你知道HashMap的工作原理吗?
通过hash的方法,通过put和get存储和获取对象。存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Facotr则resize为原来的2倍)。获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来,在Java 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

3. 你知道get和put的原理吗?equals()和hashCode()的都有什么作用?
通过对key的hashCode()进行hashing,并计算下标( n-1 & hash),从而获得buckets的位置。如果产生碰撞,则利用key.equals()方法去链表或树中去查找对应的节点

4. 你知道hash的实现吗?为什么要这样实现?
在Java 1.8的实现中,是通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),主要是从速度、功效、质量来考虑的,这么做可以在bucket的n比较小的时候,也能保证考虑到高低bit都参与到hash的计算中,同时不会有太大的开销。

5. 如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?
如果超过了负载因子(默认0.75),则会重新resize一个原来长度两倍的HashMap,并且重新调用hash方法。



0 0
原创粉丝点击