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. 串口字符串-HEX格式

    串口字符串-HEX格式 C++SerialSerialPortHEX 介绍 串口通信过程中 通常涉及一个数据的模拟过程以及数据发送过程, 一般来说, 我们会发送一串指令给下位机 68 05 00 84 ...

  2. C++-doctest-测试框架

    C++-doctest-测试框架 C++UnitTestDoctest 测试框架 doctest 是用过的最简单好用的的单元测试框架, 只需要引用 一个头文件即可 无main 函数的测试样例 #def ...

  3. [转]探索 Android 内存优化方法

    前言 这篇文章的内容是我回顾和再学习 Android 内存优化的过程中整理出来的,整理的目的是让我自己对 Android 内存优化相关知识的认识更全面一些,分享的目的是希望大家也能从这些知识中得到一些 ...

  4. html+css的用户注册界面

    注册界面样图 代码实现 html部分 <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  5. Flutter自己实现一个ProgressHUD

    用惯了iOS的SVProgressHUD,但是在flutter pub上的并没有找到类似的实现,于是自己实现一个 主要实现四个基本功能 Loading显示 成功显示 错误显示 进度显示:环形进度条和文 ...

  6. 《Cisco防火墙》一2.4 总结

    本节书摘来自异步社区<Cisco防火墙>一书中的第2章,第2.4节,作者 [巴西]Alexandre M.S.P. Moraes,更多章节内容可以访问云栖社区"异步社区" ...

  7. 团队一致性的PHP开发环境之Docker

    docker php环境模型 docker 简介 Docker 是一个开源的应用容器引擎 让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现 ...

  8. 播放音乐(mciSendString)

    1.需要引用命名空间using System.Runtime.InteropServices; 这里只是做了个简单的播放功能,想了解更多查看它的官方文档 [DllImport("winmm. ...

  9. 如何选择IO调度器

    概述 由于对multi-quque的IO调度算法不太熟悉,为了避免误人子弟,本文暂时只会介绍如何选择single-queue的IO调度算法.等将来对multi-queue有充分认识后再补充. 如果不清 ...

  10. IDEA破解,自动激活【2020年版本也可以破解】

    破解 在破解之前,需要下载的文件有两个ideaIU-2019.3.3.exe.jetbrains-agent-latest.zip,前者是程序安装包,后者是破解补丁包(PS:补丁包里面有使用说明,下面 ...