1.HashMap简介(本文是按照JDK1.8进行解析)

HashMap位于JDK自带jar包rt.jar的java.util目录下。 HashMap是一个散列表,存储的内容是键值对<key,value>映射。

HashMap继承于AbstractMap,实现了Map、Cloneable、Serializable接口 HashMap是线程不安全的,其中key、value都可以为null,且是无序的。

2.HashMap的数据结构

通常的数据结构有数组和链表两种,他们各有优缺点。

数组:如下图示:

数组的存储区间是连续的,即使对应位置值为空也需要分配内存,所以占用内存较多,但是数组查找数据很容易,只需要知道对应的下标值即可,二分查找时间复杂度为O(1);

但是数组新增和删除元素比较复杂,比如现在需要删除下标为3的Arr4,下标为3后面的元素全部需要左移一位,在下标为3后面插入一条数据同理,后面的数据全部需要右移。

总结

数组的优点是:查找容易

数组的缺点是:新增和删除复杂、占用内存严重

链表:如下图示:

链表的存储区间很离散,占用内存的数据都是有效数据,占用内存较少,插入数据容易,比如在节点2和节点3之间插入一条数据,只需将节点2的next指向新节点,新节点的next指向节点3即可;

删除节点3,则值需将节点2的next指向节点4即可,都不影响其他的节点,但是如果需要查询一个节点比较困难,需要从节点1开始遍历每个节点,才可以找到需要查询的节点位置。

总结

链表的优点是:新增和删除容易、占用内存较少

链表的缺点是:查询比较复杂

而HashMap是综合了数组和链表的特性,实现了即查询容易,插入和删除也容易的数据结构;如下图示:

可见HashMap的数据结构其实还是数组,只是数组里存储的数据是一个链表。

那么HashMap是怎么做到的呢?

首先HashMap需要有一个链表的线性数组,Node<K,V>[] table

Node是HashMap的内部类,存储在数组指定位置的节点,主要属性有hash、key、value和next

接下来再分析下HashMap是怎么工作的?

1.HashMap初始化

HashMap主要有四个构造方法,主要是初始化HashMap的loadFactor(加载因子)和threshold (扩容长度)

loadFactor是HashMap的加载因子,默认是0.75,HashMap默认长度是16,当HashMap中存入的数据长度达到总长度size*loadFactor的时候就需要开始扩容,

也就是说当HashMap使用到12的时候就需要开始扩容,默认是对数组进行2倍的扩容,扩容后的总长度就是threshold。

2.put的流程

当HashMap存入数据调用put方法,先根据传入的key值,取对应的哈希码,获取到一个int类型的hash值,这个hash值对应的数字就是该数据需要存入到数组对应的下标位置,

如存入一个key通过计算得到hash值为2,则该数据就存入table[2]中。这里会有两种情况,一种是插入之前table[2]的位置还没有存入数据,则直接将数据存入table[2]的位置,当是如果

此时table[2]的位置已经存有数据,则通过链表的形式,将数据插入到table[2]的链表尾,如下图示:

当key获取到的hash值对应的位置已经存在数据的时候,不是立马将数据存入到对应链表的尾部,而是先判断这个key是否已经存在table中,比如现在再重新put一遍<"赵五","30岁">,通过key的hash值知道需要放在table[1]的位置,那么会从链表头开始挨个判断key值是否等于当前的key值,如果两个key和hash值都相等,则不会加入到链表尾,而是直接更新value值

3.get的流程

现在由于知道了HashMap是如何存入数据的,现在从HashMap取数据就相对比较容易理解了,先是通过key取对应的hash值,就可以很容易定位到数据是存在table的那个位置,如果对应的位置链表长度只有1,且key相等,则取出value;如果链表长度不为1,则遍历链表,挨个判断key是否等于需要查找的key,找到了便返回对应的value

4.扩容resize的流程

当HashMap一直put操作,HashMap容量是有限的,就需要进行扩容,HashMap会有一个阈值,就是当前数组的长度 * 加载因子(默认是0.75)

由于数组是无法自动扩容的,所以需要创建新的数组来替换旧的数组。如果不进行扩容,还是默认的长度16的话,如果插入160条数据的话,那么数组每一个位置的链表长度平均都为10,会影响查询的效率;

hashMap扩容的时候默认是对当前数组进行2倍扩容,也就是默认是长度为16,则扩容一次后长度为32,扩容两次就是64。

另外扩容之后原先的table中的数据位置可能会进行改变,因为通过hash值获取到的位置可能已经不再是原来的位置了,每个元素都需要重新计算新的位置,所以resize方法是比较消耗性能的。

关于HashMap的具体实现

tips:

1.HashMap的长度和HashMap中的数组长度是两个概念,比如新建一个HashMap,put一条数据,此时数组的长度是默认的16,而HashMap的size则为1.

如果put进10条数据,且10条数据的hash值都一样,则会存入数组的同一个链表下,此时数组只有一个位置存有数据,但是HashMap的size则为10

HashMap基本介绍的更多相关文章

  1. Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

    概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...

  2. Java 集合系列 09 HashMap详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  3. JAVA HashMap详细介绍和示例

    http://www.jb51.net/article/42769.htm 我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.   第1部分 HashMa ...

  4. 【转】Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例

    概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...

  5. HashMap简单介绍

    哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表. 一.什么是哈希表 在讨论哈希表之 ...

  6. HashMap方法介绍

    1. Map的遍历方式 (1) for each map.entrySet() Map<String, String> map = new HashMap<String, Strin ...

  7. Java HashMap详细介绍和使用示例

    ①对HashMap的整体认识 HashMap是一个散列表,它存储的内容是键值对(key-value)映射. HashMap继承于AbstractMap,实现了Map.Cloneable.java.io ...

  8. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  9. Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

随机推荐

  1. CodeForces 674C Levels and Regions

    #include<bits/stdc++.h> using namespace std; const int maxn=2e5+5; int N,K,head,tair; int q[ma ...

  2. Firefox 66 发布,阻止网站自动播放声音

    Firefox 66 发布了,此版本在桌面版中带来的新特性包括: Firefox 现在阻止网站自动播放声音,如果需要可以单独调整 改进的搜索体验: 当打开许多选项卡时,可以更快地查找特定网页:现在可以 ...

  3. Elasticsearch: 权威指南 » 深入搜索 » 多字段搜索 » 多数字段 good

      跨字段实体搜索  » 多数字段编辑 全文搜索被称作是 召回率(Recall) 与 精确率(Precision) 的战场: 召回率 --返回所有的相关文档:精确率 --不返回无关文档.目的是在结果的 ...

  4. 自定义Bootstrap样式弹出框

    最近做的一些功能需要用到Bootstrap,然而原来的系统并没有引入Bootstrap,为了新写的控件能够应用于老的页面,又不需要在老的页面上引入全套的Bootstrap文件决定写一个模仿Bootst ...

  5. 通过fiddler抓取IDEA的请求

    2019独角兽企业重金招聘Python工程师标准>>> 因为fiddler默认是代理的8888端口,所以设置一下IDEA的请求使用本地的8888作为代理发出. 1."EDI ...

  6. DFS--POJ 1190 生日蛋糕

    Description 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri ...

  7. 图论--最短路--第K短路(IDA*)(IDA Star)模板

    #include <iostream> #include <cstdio> #include <cstring> #include <queue> us ...

  8. Arduino入门简介

    先说Arduino是什么? 1.一个平台,开源电子原型平台,包含小板子(UNO开发板.PRO Mini板登)和电脑上安装的软件(IDE). 2.能通过传感器(红外.温度.超声波传感器...)等来感知环 ...

  9. 【网络基础】ARP地址解析协议

    ARP(Address Rssolution Protocol) 地址解析协议 用于将IP地址解析为MAC地址. MAC地址是设备的物理地址,是被分配给每一个网络接口卡的全球唯一序号. 全球唯一:理论 ...

  10. 送你一份Redis书单,以后使用缓存的问题不用再问我啦!

    点击蓝色"程序员书单"关注我哟 加个"星标",每天带你读好书!