在JDK1.8后,对HashMap源码进行了更改,引入了红黑树。
在这之前,HashMap实际上就是就是数组+链表的结构,由于HashMap是一张哈希表,其会产生哈希冲突,为了解决哈希冲突,HashMap采用了开链法,即对于用对象hashCode值计算哈希表数组下表时,当出现相同情况时,会在相同的地方追加形成链表的形式。对于分布均匀的情况下,仅仅是一个一维数组,查询时时间复杂度为O(1),当分布不均匀的时候,在有的地方会形成链表,极端情况下完全退化成一个链表,查询时就需要遍历整个链表,时间复杂度就为O(n),极为耗时。
在引入红黑树后,当满足一定条件时,链表就会转换成一棵红黑树。红黑树是一种AVL树(自平衡查找二叉树),相比于链表,其查找时的时间复杂度还是很优秀的(O(logn))!

先了解一下HashMap的模型:

其中的Node结点存放我们的键值对<K, V>;
首先,我们先了解HashMap给出的几个重要指标:

 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;  // 默认的初始化容量大小为16
static final int MAXIMUM_CAPACITY = 1 << 30; // HashMap最大容量1G
static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认负载因子值0.75,用于扩容时的计算
static final int TREEIFY_THRESHOLD = 8; // 树的阈值,当链表长度大于等于8时,由链表转换成红黑树
static final int UNTREEIFY_THRESHOLD = 6; // 链表的阈值,暂时不清楚
static final int MIN_TREEIFY_CAPACITY = 64; // 最小树容量64

以上就是几个基本指标,其规定了在以后操作中的界限!
其中Node<K, V>是一个内部类,封装了这个结点的所有信息,有如下几个成员

 final int hash;
final K key;
V value;
Node<K,V> next;

key和value不必多说,其中的hash是利用key对象的hashCode计算得到的,具有唯一性:

  static final int hash(Object key) {
int h;
// 可以看到hash是根据对象的hashCode值来计算
// hashCode是一个int值,有32位
// 最后改变的是其低16位
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

其中的next就是为了解决哈希冲突,当产生哈希冲突时,next就可以指向一张链表,或者一棵黑树!

接下来是几个重要的成员:

  transient Node<K,V>[] table; // 这就是真正的HashMap,一张哈希表,实际上就是由Node结点组成的一维数组
transient int size; // 记录table中真正有效的结点个数,也就是键值对的个数
int threshold; // 用来记录当前容量下,最适合存放多少键值对(容量*负载因子)
final float loadFactor; // 负载因子,若在构造方法没有特别设置,都是默认0.75
transient int modCount; // 用来记录操作数

看到这,我们先不急着往下进行,先仔细分析下这些成员之间的关系:
table:真正开辟的空间,其length就是真正的容量大小
size: 真正使用的空间,总的键值对的个数
threshold:这个就比较有意思,其决定了是否需要进行扩容的操作,是一个阈值!
比如说,在初始化时,默认的容量是16,那么table的length就是16,其threshold=容量×负载因子=16×0.75=12,这就代表着,当size大于12时,就会进行扩容(容量会×2,threshold会根据新容量重新计算)的操作!
这样做的目的很明确,就是为了减少哈希冲突!有效元素的个数少于哈希表的总大小时,其产生哈希冲突的可能性一定是小于相等情况的!
综上可知,在非极限情况下(容量=threshold=MAXIMUM_CAPACITY=2^30)时,threshold总是小于容量,size总是不大于threshold!
这一切的做法,都是为了能够减少哈希冲突产生的可能性!

说到这里还是不能往下进行,我们需要知道Node中的hash成员是如何与table中的下标产生对应关系的,以及哈希冲突是如何产生的:

首先是关于hash值和table下标的映射:

 index =   hash  & (table.length - 1)

这是一个非常巧妙的运算,当table.length满足二的整数幂时,就满足:
hash & (table.length - 1) == hash % table.length
例如:2%8 = 2 即:
0000 0010 2
&
0000 0111 (8 - 1)
0000 0010
二的整数幂减一得到的二进制数,其有效位全是1,通过&可以直接得到符合条件的有效位的值!
其实就是取余,用余数作为table的下标,而位运算的速度是比其余快的多,所以采用了这种方式!
所以这就是为什么table的大小必须是二的整数幂,以及扩容时都是乘2!

哈希冲突的产生:
以初始table.length = 16为例
对于hash = 1, 和 hash = 17来说,其对于16取余的结果都是1,那么这两个不同的hash值对应了同一个table的下标,这就产生了哈希冲突!

先将HashMap简单介绍到这,后续我会继续分析HashMap,若有错误或不足之处,还请指出!

我在CSDN也放了一篇【Java】HashMap源码分析——基本概念

【Java】HashMap源码分析——基本概念的更多相关文章

  1. Java HashMap源码分析(含散列表、红黑树、扰动函数等重点问题分析)

    写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...

  2. java HashMap源码分析(JDK8)

    这两天在复习JAVA的知识点,想更深层次的了解一下JAVA,所以就看了看JAVA的源码,把自己的分析写在这里,也当做是笔记吧,方便记忆.写的不对的地方也请大家多多指教. JDK1.6中HashMap采 ...

  3. Java HashMap源码分析

    貌似HashMap跟ConcurrentHashMap是面试经常考的东西,抽空来简单分析下它的源码 构造函数 /** * Constructs an empty <tt>HashMap&l ...

  4. 【Java】HashMap源码分析——常用方法详解

    上一篇介绍了HashMap的基本概念,这一篇着重介绍HasHMap中的一些常用方法:put()get()**resize()** 首先介绍resize()这个方法,在我看来这是HashMap中一个非常 ...

  5. 【JAVA集合】HashMap源码分析(转载)

    原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储 ...

  6. Java集合源码分析(四)HashMap

    一.HashMap简介 1.1.HashMap概述 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射.此类不保证映射的顺序,假定哈希函数将元素 ...

  7. Java BAT大型公司面试必考技能视频-1.HashMap源码分析与实现

    视频通过以下四个方面介绍了HASHMAP的内容 一. 什么是HashMap Hash散列将一个任意的长度通过某种算法(Hash函数算法)转换成一个固定的值. MAP:地图 x,y 存储 总结:通过HA ...

  8. Java源码解析——集合框架(五)——HashMap源码分析

    HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...

  9. Java 集合源码分析(一)HashMap

    目录 Java 集合源码分析(一)HashMap 1. 概要 2. JDK 7 的 HashMap 3. JDK 1.8 的 HashMap 4. Hashtable 5. JDK 1.7 的 Con ...

随机推荐

  1. Java面试题3

    1.servlet执行流程 客户端发出http请求,web服务器将请求转发到servlet容器,servlet容器解析url并根据web.xml找到相对应的servlet,并将request.resp ...

  2. AngularJS封装webupload实现文件夹上传

    百度的webupload没有开放api获取整个文件夹的信息.本文是二次开发webupload实现获取文件夹信息. 指令封装 /** * @license lx.ui.framework v1.0.0 ...

  3. Chapter7 抑癌基因

    一.实验证明,如果肿瘤不是肿瘤病毒产生时,与正常细胞融合后,其恶性表型是隐形的 二. 家族性视网膜母细胞瘤的形成模型 如何使得一个细胞获得两个突变(两次随机的突变可能性太小) 模型一:有丝分裂的同源重 ...

  4. MySQL导入SQL语句报错 : MySQL server has gone away (已解决)

    MySQL server has gone away 解决的方法其实很简单,我相信也有很多人遇到了这个问题.比如DZ论坛,安装好服务器,但是清空缓存等操作数据库的动作,运行时间稍长就会出现 MySQL ...

  5. 关于wifi网络基本原理了解

    对于esp32,其wifi功能还是十分强大的,为了能够良好的完成wifi的相关开发,这里需要计算机网络的结构体系进行大致的了解. 一.网络结构分层 对于计算机网络结构,大体上可以分为5层结构: 物理层 ...

  6. linux 修改用户密码的几种方法

    1.passwd 命令,手动修改: [root@localhost testuser]# passwd testuser Changing password for user testuser. Ne ...

  7. Microsoft在8月7号发布的帮助文档更新中,HelpLibrary2安装Cab文档包出现签名问题

    在VS 2017 8月2号发布15.7.6版本后,在8月7号推送了helpview程序中的绝大部分更新文档,在本次推送中多数Cab文件出现了无法进行安装的签名问题, 不论是单个下载,还是删除本地所有已 ...

  8. Windows 远程栈溢出挖掘与利用

    缓冲区溢出攻击很容易被攻击者利用,因为 C 和 C++等语言并没有自动检测缓冲区溢出操作,同时程序编写人员在编写代码时也很难始终检查缓冲区是否可能溢出.利用溢出,攻击者可以将期望数据写入漏洞程序内存中 ...

  9. SpringCloud总结

    初级入门使用轮廓,整理一下思路

  10. Win10 Hyper-v下虚拟机使用无线网络

    首先要承认一点的是写这个随笔更大的初衷是想吐槽,搜了半天,全是一种方法,就是创建一个新的网络适配器,配置为外部网络啥啥啥,用倒是能用,就是网速那叫一个感人,我的是电信百兆光纤网页打开都如蜗牛爬,无法忍 ...