声明,本文用得是jdk1.8html
前面已经讲了Collection的总览和剖析List集合以及散列表、Map集合、红黑树的基础了:java
本篇主要讲解HashMap,以及涉及到一些与hashtable的比较~算法
看这篇文章以前最好是有点数据结构的基础:数组
固然了,若是讲得有错的地方还请你们多多包涵并不吝在评论去指正~安全
首先看看HashMap的顶部注释说了些什么:微信
再来看看HashMap的类继承图:数据结构
下面咱们来看一下HashMap的属性:post
成员属性有这么几个:性能
再来看一下hashMap的一个内部类Node:测试
咱们知道Hash的底层是散列表,而在Java中散列表的实现是经过数组+链表的~
再来简单看看put方法就能够印证咱们的说法了:数组+链表-->散列表
咱们能够简单总结出HashMap:
HashMap的构造方法有4个:
在上面的构造方法最后一行,咱们会发现调用了tableSizeFor()
,咱们进去看看:
这是位运算算法,具体流程可参考:
看完上面可能会感到奇怪的是:为啥是将2的整数幂的数赋给threshold?
capacity * load factor
才对的。其实这里仅仅是一个初始化,当建立哈希表的时候,它会从新赋值的:
至于别的构造方法都差很少,这里我就不细讲了:
put方法能够说是HashMap的核心,咱们来看看:
咱们来看看它是怎么计算哈希值的:
为何要这样干呢??咱们通常来讲直接将key做为哈希值不就行了吗,作异或运算是干吗用的??
咱们看下来:
咱们是根据key的哈希值来保存在散列表中的,咱们表默认的初始容量是16,要放到散列表中,就是0-15的位置上。也就是tab[i = (n - 1) & hash]
。能够发现的是:在作&
运算的时候,仅仅是后4位有效~那若是咱们key的哈希值高位变化很大,低位变化很小。直接拿过去作&
运算,这就会致使计算出来的Hash值相同的不少。
而设计者将key的哈希值的高位也作了运算(与高16位作异或运算,使得在作&运算时,此时的低位其实是高位与低位的结合),这就增长了随机性,减小了碰撞冲突的可能性!
下面咱们再来看看流程是怎么样的:
新值覆盖旧值,返回旧值测试:
接下来咱们看看resize()
方法,在初始化的时候要调用这个方法,当散列表元素大于capacity * load factor
的时候也是调用resize()
接下来咱们看看getNode()
是怎么实现的:
再来看看removeNode()
的实现:
从存储结构和实现来说基本上都是相同的。它和HashMap的最大的不一样是它是线程安全的,另外它不容许key和value为null。Hashtable是个过期的集合类,不建议在新代码中使用,不须要线程安全的场合能够用HashMap替换,须要线程安全的场合能够用ConcurrentHashMap替换
Hashtable具体阅读源码可参考:
在JDK8中HashMap的底层是:数组+链表(散列表)+红黑树
在散列表中有装载因子这么一个属性,当装载因子*初始容量小于散列表元素时,该散列表会再散列,扩容2倍!
装载因子的默认值是0.75,不管是初始大了仍是初始小了对咱们HashMap的性能都很差
初始容量的默认值是16,它也同样,不管初始大了仍是小了,对咱们的HashMap都是有影响的:
从源码上咱们能够发现:HashMap并非直接拿key的哈希值来用的,它会将key的哈希值的高16位进行异或操做,使得咱们将元素放入哈希表的时候增长了必定的随机性。
还要值得注意的是:并非桶子上有8位元素的时候它就能变成红黑树,它得同时知足咱们的散列表容量大于64才行的~
明天要是无心外的话,可能会写TreeMap,敬请期待哦~~~~
文章的目录导航:zhongfucheng.bitcron.com/post/shou-j…
若是文章有错的地方欢迎指正,你们互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同窗,能够关注微信公众号:Java3y。为了你们方便,刚新建了一下qq群:742919422,你们也能够去交流交流。 谢谢支持了!但愿能多介绍给其余有须要的朋友
参考资料: