以下基于 JDK1.7 分析。

如图所示,HashMap 底层是基于数组和链表实现的。其中有两个重要的参数:

  • 容量
  • 负载因子

容量的默认大小是 16,负载因子是 0.75,当 HashMapsize > 16*0.75 时就会发生扩容(容量和负载因子都可以自由调整)。

put 方法

首先会将传入的 Key 做 hash 运算计算出 hashcode,然后根据数组长度取模计算出在数组中的 index 下标。

由于在计算中位运算比取模运算效率高的多,所以 HashMap 规定数组的长度为 2^n 。这样用 2^n - 1 做位运算与取模效果一致,并且效率还要高出许多。

由于数组的长度有限,所以难免会出现不同的 Key 通过运算得到的 index 相同,这种情况可以利用链表来解决,HashMap 会在 table[index]处形成链表,采用头插法将数据插入到链表中。

get 方法

get 和 put 类似,也是将传入的 Key 计算出 index ,如果该位置上是一个链表就需要遍历整个链表,通过 key.equals(k) 来找到对应的元素。

遍历方式

1
2
3
4
5
Iterator<Map.Entry<String, Integer>> entryIterator = map.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<String, Integer> next = entryIterator.next();
System.out.println("key=" + next.getKey() + " value=" + next.getValue());
}
1
2
3
4
5
6
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()){
String key = iterator.next();
System.out.println("key=" + key + " value=" + map.get(key)); }

大专栏  HashMap底层分析>

1
2
3
map.forEach((key,value)->{
System.out.println("key=" + key + " value=" + value);
});

强烈建议使用第一种 EntrySet 进行遍历。

第一种可以把 key value 同时取出,第二种还得需要通过 key 取一次 value,效率较低, 第三种需要 JDK1.8 以上,通过外层遍历 table,内层遍历链表或红黑树。

notice

在并发环境下使用 HashMap 容易出现死循环。

并发场景发生扩容,调用 resize() 方法里的 rehash() 时,容易出现环形链表。这样当获取一个不存在的 key 时,计算出的 index 正好是环形链表的下标时就会出现死循环。

所以 HashMap 只能在单线程中使用,并且尽量的预设容量,尽可能的减少扩容。

JDK1.8 中对 HashMap 进行了优化:
hash 碰撞之后写入链表的长度超过了阈值(默认为8),链表将会转换为红黑树

假设 hash 冲突非常严重,一个数组后面接了很长的链表,此时重新的时间复杂度就是 O(n)

如果是红黑树,时间复杂度就是 O(logn)

大大提高了查询效率。

附录:

什么是HashMap?

高并发下的HashMap

什么是ConcurrentHashMap?

什么是红黑树?

HashMap底层分析的更多相关文章

  1. HashMap 底层分析

    以下基于 JDK1.7 分析 如图所示,HashMap底层是基于数组和链表实现的,其中有两个重要的参数: ---容量 ---负载因子 容量的默认大小是16,负载因子是0.75,当HashMap的siz ...

  2. HashMap底层原理分析(put、get方法)

    1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那ha ...

  3. Java——HashMap底层源码分析

    1.简介 HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap 最多只允许一条记录的key为 nu ...

  4. ArrayList、LinkedList、HashMap底层实现

    ArrayList 底层的实现就是一个数组(固定大小),当数组长度不够用的时候就会重新开辟一个新的数组,然后将原来的数据拷贝到新的数组内. LinkedList 底层是一个链表,是由java实现的一个 ...

  5. HashMap的分析(转)

    一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.(除了不同步和允许使用 null 之外,HashMap  ...

  6. HashMap底层结构、原理、扩容机制

    https://www.jianshu.com/p/c1b616ff1130 http://youzhixueyuan.com/the-underlying-structure-and-princip ...

  7. HashMap底层数据结构和算法解析

    1.Hash Map的数据结构? A:哈希表结构(链表散列:数组+链表)实现,结合数组和链表的优点.当链表长度超过8时,链表转换为红黑树. transient Node<K,V>[] ta ...

  8. hashMap 底层原理+LinkedHashMap 底层原理+常见面试题

    1.源码 java1.7    hashMap 底层实现是数组+链表 java1.8 对上面进行优化  数组+链表+红黑树 2.hashmap  是怎么保存数据的. 在hashmap 中有这样一个结构 ...

  9. [转]java 的HashMap底层数据结构

    java 的HashMap底层数据结构   HashMap也是我们使用非常多的Collection,它是基于哈希表的 Map 接口的实现,以key-value的形式存在.在HashMap中,key-v ...

随机推荐

  1. geodjango七日学习笔记 (7.30整理本地笔记上传到网络)

    第一天进行到现在,在开端的尾巴,想起来写一个学习笔记, 开发环境已搭好,用的是pycharm 环境是本机已有的interpreter python3.7   接下来要做的是新建一个geodjango项 ...

  2. Codeforces 1294E - Obtain a Permutation

    题目大意: 给定一个n*m的矩阵 可以更改任意一个位置的值 也可以选择一整列全部往上移动一位,最上方的数移动到最下方 问最少操作多少次可以把这个矩阵移动成 1 2 3 ... m m+1 m+2 m+ ...

  3. python3拆包详解

    对于可迭代对象,如元组.列表.字符串.集合.字典这些可迭代对象都可以被拆包,拆包是指将一个结构中的数据拆分为多个单独变量中.拆包的方式大致有两种,一种是以变量的方式来接收,另一种是用'*'号.下面先讲 ...

  4. Excel文件比较工具的使用

    本工具用于比较两个文件夹中对应Excel工作簿中单元格数据是否不同. 如果有内容不同的单元格,就在结果报告中表示出来. 点击如下链接,下载. Excel文件比较工具.rar 解压缩后,看到1个exe文 ...

  5. webstorm更换了项目启动后仍然是之前的项目(问题解决)

    1. 2.

  6. 关于SG函数

    Sprague-Grundy定理(SG定理): 游戏和的SG函数等于各个游戏SG函数的Nim和.这样就可以将每一个子游戏分而治之,从而简化了问题.而Bouton定理就是Sprague-Grundy定理 ...

  7. Java实战——简介

    由于下学期要学习JavaEE所以打算将JavaSE的知识再重新学习一遍,打好基础的同时也希望自己有新的收获和更深刻的理解. 这次复习主要是参考廖雪峰老师的java教程,每学习完一章对其中一些要点进行总 ...

  8. 四十二、LAMP与LNMP web架构深度优化实战-第一部

    1.nginx.conf配置文件基本参数优化 1.1 隐藏nginx header内版本号信息 一些特定的系统及服务漏洞一般都和特定的软件版本号有关,我们应尽量隐藏服务器的敏感信息(软件名称及版本等信 ...

  9. windows10使用npm安装vue、vue-cli

    从网上下载了一个免费的vue.js前端模板,准备和Django整合出一个项目出来,然后发现前端代码都是.vue文件,已经整合过.html,很容易,感觉这个.vue的前端稍微复杂一些 本文主要参考博客及 ...

  10. JSP和EL和JSTL

    什么是JSP Java Server Page的缩写从用户角度看待,就是一个网页从程序员角度看待,其实是一个java类,它继承了Servlet,所以可以直接说jsp就是一个Servlet 为什么会有J ...