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. [SVN] Couldn't perform atomic initialization

    svn: Commit failed (details follow): svn: Couldn't perform atomic initialization It was because the ...

  2. 动画图解Git命令

    ​Git是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理,是目前使用范围最广的版本管理工具 尽管Git是一个非常强大的工具,但我认为大多数人都会同意我的说法,即它也可以 ...

  3. 理解分布式一致性:Raft协议

    理解分布式一致性:Raft协议 什么是分布式一致性 Leader选举 日志复制流程 term选举周期 timeout 选举和选举timeout 选举分裂 日志复制和心跳timeout 在分布式系统中, ...

  4. 二进制安装MySQL及破解密码

    二进制安装MySQL及破解密码 1.确保系统中有依赖的libaio 软件,如果没有: yum -y install libaio 2.解压二进制MySQL软件包 tar xf mysql-5.7.24 ...

  5. SSH公钥登录和RSA非对称加密

    SSH登录方式 接触过Linux服务器的同学肯定用过SSH协议登录系统,通常SSH协议都有两种登录方式:密码口令登录和公钥登陆. 一.密码口令(类似于账号密码登录) 1.客户端连接服务器,服务器把公钥 ...

  6. 聊聊flink的BlobStoreService

    序 本文主要研究一下flink的BlobStoreService BlobView flink-release-1.7.2/flink-runtime/src/main/java/org/apache ...

  7. time wait 整理

    目录 状态转换图 1.谁会进入time wait状态: 主动发起断开连接的一方调用close()函数发送FIN并进入FIN WAIT 1状态,当收到对面反馈的ack之后会进入FIN WAIT2状态.之 ...

  8. Integer和int及String的总结

    秉承着总结发表是最好的记忆,我把之前遇到的问题在这里总结和大家分享一下,希望大家共同进步: 一.Integer和int首先说下自动拆装箱,基本数据类型转换为包装类型的过程叫装箱,反之则是拆箱,其中最特 ...

  9. Taurus.MVC 2.3.2 :WebAPI 文档集成测试功能及附加<%# JS执行功能语法 %>

    前言: 前些天有网友提到了那个界面丑陋的SwaggerUI,让我想起了多年前实现的WebAPI文档未完成的功能点,于是,动手了,便有了本文的内容. 开源地址:https://github.com/cy ...

  10. Spring Boot学习 之 Spring Boot Actuator(一)

    Spring Boot版本:2.1.4.RELEASE 启用: spring-boot-actuator模块提供了一系列的用于监控的端点.最简单的开启这个功能的方法就是,在pom文件中添加如下的依赖. ...