前言

声明,本文用得是jdk1.8

前面已经讲了Collection的总览和剖析List集合以及散列表、Map集合、红黑树的基础了:

本篇主要讲解HashMap,以及涉及到一些与hashtable的比较~

看这篇文章之前最好是有点数据结构的基础:

当然了,如果讲得有错的地方还请大家多多包涵并不吝在评论去指正~

一、HashMap剖析

首先看看HashMap的顶部注释说了些什么:

再来看看HashMap的类继承图:

下面我们来看一下HashMap的属性:

成员属性有这么几个:

再来看一下hashMap的一个内部类Node:

我们知道Hash的底层是散列表,而在Java中散列表的实现是通过数组+链表的~

再来简单看看put方法就可以印证我们的说法了:数组+链表-->散列表

我们可以简单总结出HashMap:

  • 无序,允许为null,非同步
  • 底层由散列表(哈希表)实现
  • 初始容量和装载因子对HashMap影响挺大的,设置小了不好,设置大了也不好

1.1HashMap构造方法

HashMap的构造方法有4个:

在上面的构造方法最后一行,我们会发现调用了tableSizeFor(),我们进去看看:

这是位运算算法,具体流程可参考:

看完上面可能会感到奇怪的是:为啥是将2的整数幂的数赋给threshold

  • threshold这个成员变量是阈值,决定了是否要将散列表再散列。它的值应该是:capacity * load factor才对的。

其实这里仅仅是一个初始化,当创建哈希表的时候,它会重新赋值的:

至于别的构造方法都差不多,这里我就不细讲了:

1.2put方法

put方法可以说是HashMap的核心,我们来看看:

我们来看看它是怎么计算哈希值的:

为什么要这样干呢??我们一般来说直接将key作为哈希值不就好了吗,做异或运算是干嘛用的??

我们看下来:

我们是根据key的哈希值来保存在散列表中的,我们表默认的初始容量是16,要放到散列表中,就是0-15的位置上。也就是tab[i = (n - 1) & hash]。可以发现的是:在做&运算的时候,仅仅是后4位有效~那如果我们key的哈希值高位变化很大,低位变化很小。直接拿过去做&运算,这就会导致计算出来的Hash值相同的很多。

而设计者将key的哈希值的高位也做了运算(与高16位做异或运算,使得在做&运算时,此时的低位实际上是高位与低位的结合),这就增加了随机性,减少了碰撞冲突的可能性!

下面我们再来看看流程是怎么样的:

新值覆盖旧值,返回旧值测试:

接下来我们看看resize()方法,在初始化的时候要调用这个方法,当散列表元素大于capacity * load factor的时候也是调用resize()

1.3get方法

接下来我们看看getNode()是怎么实现的:

1.4remove方法

再来看看removeNode()的实现:

二、HashMap与Hashtable对比

从存储结构和实现来讲基本上都是相同的。它和HashMap的最大的不同是它是线程安全的,另外它不允许key和value为null。Hashtable是个过时的集合类,不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换

Hashtable具体阅读源码可参考:

四、总结

在JDK8中HashMap的底层是:数组+链表(散列表)+红黑树

在散列表中有装载因子这么一个属性,当装载因子*初始容量小于散列表元素时,该散列表会再散列,扩容2倍!

装载因子的默认值是0.75,无论是初始大了还是初始小了对我们HashMap的性能都不好

  • 装载因子初始值大了,可以减少散列表再散列(扩容的次数),但同时会导致散列冲突的可能性变大(散列冲突也是耗性能的一个操作,要得操作链表(红黑树)
  • 装载因子初始值小了,可以减小散列冲突的可能性,但同时扩容的次数可能就会变多!

初始容量的默认值是16,它也一样,无论初始大了还是小了,对我们的HashMap都是有影响的:

  • 初始容量过大,那么遍历时我们的速度就会受影响~
  • 初始容量过小,散列表再散列(扩容的次数)可能就变得多,扩容也是一件非常耗费性能的一件事~

从源码上我们可以发现:HashMap并不是直接拿key的哈希值来用的,它会将key的哈希值的高16位进行异或操作,使得我们将元素放入哈希表的时候增加了一定的随机性

还要值得注意的是:并不是桶子上有8位元素的时候它就能变成红黑树,它得同时满足我们的散列表容量大于64才行的~


明天要是无意外的话,可能会写TreeMap,敬请期待哦~~~~

文章的目录导航https://zhongfucheng.bitcron.com/post/shou-ji/gong-zhong-hao-wen-zhang-zheng-li

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。

谢谢支持了!希望能多介绍给其他有需要的朋友

参考资料:

HashMap就是这么简单【源码剖析】的更多相关文章

  1. HashMap源码剖析

    HashMap源码剖析 无论是在平时的练习还是项目当中,HashMap用的是非常的广,真可谓无处不在.平时用的时候只知道HashMap是用来存储键值对的,却不知道它的底层是如何实现的. 一.HashM ...

  2. 转:【Java集合源码剖析】HashMap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票 ...

  3. LinkedHashMap就这么简单【源码剖析】

    前言 声明,本文用得是jdk1.8 前面已经讲了Collection的总览和剖析List集合以及散列表.Map集合.红黑树还有HashMap基础了: Collection总览 List集合就这么简单[ ...

  4. TreeMap就这么简单【源码剖析】

    前言 声明,本文用得是jdk1.8 前面章节回顾: Collection总览 List集合就这么简单[源码剖析] Map集合.散列表.红黑树介绍 HashMap就是这么简单[源码剖析] LinkedH ...

  5. 【Java集合源码剖析】HashMap源码剖析

    转载出处:http://blog.csdn.net/ns_code/article/details/36034955 HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-va ...

  6. Java HashSet和HashMap源码剖析

    转自: Java HashSet和HashMap源码剖析 总体介绍 之所以把HashSet和HashMap放在一起讲解,是因为二者在Java里有着相同的实现,前者仅仅是对后者做了一层包装,也就是说Ha ...

  7. 【转】Java集合:HashMap源码剖析

    Java集合:HashMap源码剖析   一.HashMap概述二.HashMap的数据结构三.HashMap源码分析     1.关键属性     2.构造方法     3.存储数据     4.调 ...

  8. 【java集合框架源码剖析系列】java源码剖析之HashMap

    前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...

  9. JDK1.7的HashMap的put(key, value)源码剖析

    目录 HashMap的put操作源码解析 1.官方文档 2.put(key, value) 3.完结 HashMap的put操作源码解析 1.官方文档 1.1.继承结构 java.lang.Objec ...

随机推荐

  1. vc的环境变量配置和缺少mspdb60.dll的解决方法

    vc的编译器是cl.exe,我们如果在vc中编译就不用配置环境,但是如果要在任何位置用命令提示符打开编译器cl.exe来编译程序,那么就要配置环境了. 下面我就讲讲vc的环境变量配置和缺少mspdb6 ...

  2. 开源自己用python封装的一个Windows GUI(UI Automation)自动化工具,支持MFC,Windows Forms,WPF,Metro,Qt

    首先,大家可以看下这个链接 Windows GUI自动化测试技术的比较和展望 . 这篇文章介绍了Windows中GUI自动化的三种技术:Windows API, MSAA - Microsoft Ac ...

  3. 剑指Offer-删除链表中重复的结点

    package LinkedList; /** * 删除链表中重复的结点 * 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. * 例如,链表1-> ...

  4. Django——ORM

    Object Relational Mapping(ORM) ORM介绍 ORM概念 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据 ...

  5. 详细分析du和df的统计结果为什么不一样

    今天有个人问我du和df的统计结果为什么会不同.给他解析了一番,后来想想还是写篇文章从原理上来分析分析. 我们常常使用du和df来获取目录或文件系统已占用空间的情况.但它们的统计结果是不一致的,大多数 ...

  6. java.lang.Thread、java.lang.ThreadGroup和java.lang.ThreadLocal<T>详细解读

    一.Thread类 public class Thread extends Object  impments Runnable 线程是程序中的 执行线程.java虚拟机允许应用程序并发地运行多个执行线 ...

  7. [poj3252]Round Numbers_数位dp

    Round Numbers poj3252 题目大意:求一段区间内Round Numbers的个数. 注释:如果一个数的二进制表示中0的个数不少于1的个数,我们就说这个数是Round Number.给 ...

  8. “Swift Language Version” (SWIFT_VERSION) build setting must be set to a supported value for targets which use Swift

    使用cocopod导入第三方swift包后,编译报以下错误: The "Swift Language Version" (SWIFT_VERSION) build setting ...

  9. CSS速查列表-1-(background)背景

    CSS 背景 CSS 属性定义背景效果: background-color background-image background-repeat background-attachment backg ...

  10. python爬虫遇到状态码304,705

    304状态码是什么? 如果客户端发送了一个带条件的GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个304状态码.简单的表达就是:客户端已经 ...