HashMap基本介绍
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基本介绍的更多相关文章
- Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例
概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...
- Java 集合系列 09 HashMap详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- JAVA HashMap详细介绍和示例
http://www.jb51.net/article/42769.htm 我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap. 第1部分 HashMa ...
- 【转】Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例
概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...
- HashMap简单介绍
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表. 一.什么是哈希表 在讨论哈希表之 ...
- HashMap方法介绍
1. Map的遍历方式 (1) for each map.entrySet() Map<String, String> map = new HashMap<String, Strin ...
- Java HashMap详细介绍和使用示例
①对HashMap的整体认识 HashMap是一个散列表,它存储的内容是键值对(key-value)映射. HashMap继承于AbstractMap,实现了Map.Cloneable.java.io ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例
概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...
随机推荐
- C++统一初始化语法(列表初始化)
引言 要是世上不曾存在C++14和C++17该有多好!constexpr是好东西,但是让编译器开发者痛不欲生:新标准库的确好用,但改语法细节未必是明智之举,尤其是3年一次的频繁改动.C++带了太多历史 ...
- centos7安装及部署zabbix监控
一:实验环境 server.zabbix.com-------------------- 192.168.200.11 agent.zabbix.com------------------------ ...
- 基于规则的分类——RIPPER算法
在<分类:基于规则的分类技术>中已经比较详细的介绍了基于规则的分类方法,RIPPER算法则是其中一种具体构造基于规则的分类器的方法.在RIPPER算法中,有几个点是算法的重要构成部分,需要 ...
- Spring IOC 之注册解析的 BeanDefinition
2019独角兽企业重金招聘Python工程师标准>>> DefaultBeanDefinitionDocumentReader.processBeanDefinition() 完成 ...
- du命令、df命令、磁盘分区
df:汇报文件系统的磁盘使用空间[root@localhost ~]# df文件系统 1K-块 已用 可用 已用% 挂载点/dev/sda3 29140072 1022920 28117152 4% ...
- winform练习-通过遍历Control容器中的对象统一委托事件-楼盘选择器
1.窗体布局如下,一个label标签内容如下,一个btnSave按钮,用于保存,其他九个按钮用于选择楼盘. 2. 按钮存于Control容器中,编写方法遍历容器中的button,通过条件过滤掉不是bu ...
- 201771010113 李婷华 《面向对象程序设计(java)》
一.理论知识部分 设计模式(Design pattern)是设计者一种流行的思考设计问题的方法,是一套被反复使用,多数人知晓的,经过分类编目的,代码设计经验的总结.使用设计模式是为了可重用代码.让代码 ...
- C# 数据操作系列 - 1. SQL基础操作
0.前言 前篇介绍了一些数据库的基本概念和以及一些常见的数据库,让我们对数据库有了一个初步的认识.这一篇我们将继续为C#数据操作的基础填上一个空白-SQL语句. SQL(Structured Quer ...
- 【Spark】DataFrame关于数据常用操作
文章目录 DSL语法 概述 实例操作 SQL语法 概述 实例操作 DSL语法 概述 1.查看全表数据 -- DataFrame.show 2.查看部分字段数据(有4种方法) (1) DataFram ...
- Day_11【集合】扩展案例5_对list集合对象中的元素进行反转,求最大值最小值,求元素i在list集合中首次出现的索引,将oldvalue替换为newvalue
分析以下需求,并用代码实现 定义MyArrays工具类,该工具类中有以下方法,方法描述如下: 1.public static void reverse(ArrayList<Integer> ...