java HashMap 原理
jdk1.7 和 1.8 大致相同但还是有区别,主要是数据结构的区别,1.7 为数组+链表;1.8 为数组+链表+红黑树
关键知识点
- 加载因子:装填因子,目的是何时对 map 进行扩容,默认是 0.75 即容量达到 75% 时对 map 扩容,原数组扩大为两倍长度
- 扩容阈值,根据数组长度和加载因子相乘得到的值,达到这个值就会扩容
- hash 算法:也叫hash函数,hash运算,指的是把 key 换算成数组的下标的算法(hashCode+数组长度+一系列右移和异或运算)
- hash 冲突:不同的 key 经过 hash 运算后得到了相同的数组下标(这时数组元素不止一个,解决的方式很多,java 采用 链式寻址法 也就是链表来解决)
- 数组长度默认是 16,且长度只会是 2 的指数个数(初始化指定的长度实际会是当前值最接近2的指数的值,比如指定为3,实际会是8)
- new HashMap() 时不会初始化数组,在 put 的时候才会初始化,具体是 put 时判断数组是否为空,如果为空再创建长度为 16 的数组
- 数组的元素是链表,这个说法不是特别准确,只是说可以这样理解,准确的说法是数组的元素是链表的头节点
jdk 1.7 put 过程
- 判断数组(table)是否为空,如果为空就先创建数组(put 才初始化数组,扩容阈值等也是 put 时确定,懒加载思维)
- 如果不指定长度,默认就是16
- 如果指定长度,并不是创建指定长度的数组,而是根据指定的长度得到最接近 2 的指数值,把这个值作为数组长度来初始化
- hash 运算得到数组下标 i
- 先得到 hashCode,hashCode 远远不够,还需要别的运算才能满足当前数组的下标范围
- 把 hashCode 多次右移和异或运算得到一个值(hash 值)
- 把 hash 值和数组长度-1做与运算(i = h & length-1),因为要保证这里的与运算能正确得到符合数组的下标,所以数组的长度必须是 2 的指数
- 把元素放入数组下标i的位置,分两种情况:当前位置有值和没有值
- 如果有值,table[i] 就是个链表,遍历这个链表,也会有两种情况,key 重复和不重复(使用 equals 比较),如果 key 重复就覆盖,返回原来的值,流程结束
- 如果没有值或者 key 不重复,继续往下走,执行新增逻辑,addEntry 方法
- 新增元素 addEntry 方法逻辑(如果 table[i] 为空,table[i] 就放当前 entry,如果不为空那就是个链表,头插法维护链表)
- 如果 size + 1 大于扩容阈值(长度*负载因子)会先进行扩容,table 长度变为原来的 2 倍,扩容方法是
resize(2 * teble.length)
- 如果 size + 1 不大于扩容阈值,就把 key-value 构建成一个节点(Entry 对象)采用头插法维护 table[i] 的链表
- size++,返回 null,流程结束
- 如果 size + 1 大于扩容阈值(长度*负载因子)会先进行扩容,table 长度变为原来的 2 倍,扩容方法是
jdk1.7 扩容
创建一个新的 table, 长度变为原来的 table 的两倍,首先把原来 table 的元素先全部拷贝到新的 table 中,拷贝的的过程中不是简单复制数组,而是重新 根据新的 table 长度进行哈希运算,把原来的元素放进新的 table 中,这样有个显著的特点,因为 table 变成了,所以 hash 运算得到的下标和原来的下标不一样,这样就会更少的发生 hash 冲突,从而把链表的长度变短
jdk1.7 get
只要明白 put 就应该能明白 get,因为 put 会先找一遍,如果没有再新增 entry。get 大概逻辑:
- 根据 key 得到 hashCode
- 再经过 hash 函数(多次右移+异或)得到 hash
- 根据 hash 和 数组长度-1(数组下标)进行与运算得到数组下标
- 再用 eauals 比较链表的 key,如果相等就获取返回
java HashMap 原理的更多相关文章
- Java:HashMap原理与设计缘由
前言 Java中使用最多的数据结构基本就是ArrayList和HashMap,HashMap的原理也常常出现在各种面试题中,本文就HashMap的设计与设计缘由作出一一讲解,并解答面试常见的一些问题. ...
- Java HashMap原理
HashMap存储结构 HashMap中数据的存储是由数组与链表一起实现的 数组寻址非常容易,其时间复杂度为O(1),但是当要插入或删除数据时,时间复杂度就会变为O(n).链表插入和删除操作的内存复杂 ...
- java - HashMap原理及实现 (转)
众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry.这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干. HashMap ...
- HashMap的原理与实 无锁队列的实现Java HashMap的死循环 red black tree
http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...
- Java HashMap工作原理及实现
Java HashMap工作原理及实现 2016/03/20 | 分类: 基础技术 | 0 条评论 | 标签: HASHMAP 分享到:3 原文出处: Yikun 1. 概述 从本文你可以学习到: 什 ...
- Java基础-hashMap原理剖析
Java基础-hashMap原理剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是哈希(Hash) 答:Hash就是散列,即把对象打散.举个例子,有100000条数 ...
- Hash算法及java HashMap底层实现原理理解(含jdk 1.7以及jdk 1.8)
现在很多公司面试都喜欢问java的HashMap原理,特在此整理相关原理及实现,主要还是因为很多开发集合框架都不甚理解,更不要说各种其他数据结构了,所以造成面子造飞机,进去拧螺丝. 1.哈希表结构的优 ...
- Java HashMap实现原理分析
参考链接:https://www.cnblogs.com/xiarongjin/p/8310011.html 1. HashMap的数据结构 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是 ...
- java中HashMap原理?
参考:https://www.cnblogs.com/yuanblog/p/4441017.html(推荐) https://blog.csdn.net/a745233700/article/deta ...
- Java HashMap工作原理:不仅仅是HashMap
前言: 几乎所有java程序员都用过hashMap,但会用不一定会说. 近年来hashMap是非常常见的面试题,如何为自己的回答加分?需要从理解开始. "你用过hashMap吗?" ...
随机推荐
- 从0到1手把手实现vite
什么是Vite? 法语:轻量化,快速 基于VUE3 非 打包开发服务器,请注意,它是个开发服务器哇!! 快速开发,按需编译,不再等待整个应用编译完成 基于原生模块系统ESModule实现 说白了,就是 ...
- angular--路由导航三种方法
- SpringCloud NetFlix学习
SpringCloud NetFlix 遇到记录不完全的可以看看这个人的博客 学相伴SpringCloud 微服务架构的4个核心问题? 服务很多,客户端该怎么访问? 负载均衡.反向代理,用户请求的永远 ...
- Java 进阶P-8.5+P-8.6
抛出异常 异常的抛出与声明 如果你的函数可能抛出异常,就必须在函数头部加以声明 你可以声明并不会真的抛出得异常 什么能扔? 任何继承了Throw able类的对象 Exception类继承了Throw ...
- Unity_UIWidgets - 组件Scaffold
UIWidgets - 组件Scaffold 各位兄弟姐妹,想通过Unity来开发UIWidgets的么,想通过UIWi的gets..来开发手机APP么??想么想么,哈哈哈哈哈哈哈哈. 好了,小黑不唠 ...
- ReentrantLock介绍及源码解析
ReentrantLock介绍及源码解析 一.ReentrantLock介绍 ReentrantLock是JUC包下的一个并发工具类,可以通过他显示的加锁(lock)和释放锁(unlock)来实现线程 ...
- springBoot简单记录日志
记录日志的几种方法 springboot项目内置日志框架 在配置文件中添加以下配置: logging: file: name: "./log/xxx.log" pattern: f ...
- 浅谈Pytest中的warning处理
浅谈Pytest中的warning处理 没有处理warning 我们写一个简单的测试 import pytest def test_demo(): import warnings warnings.w ...
- LeetCode_单周赛_329
2544. 交替数字和 代码1 转成字符串,逐个判断 class Solution { public int alternateDigitSum(int n) { char[] s = (" ...
- shin-monitor源码分析
在经过两年多的线上沉淀后,将监控代码重新用 TypeScript 编写,删除冗余逻辑,正式开源. 根据 shin-monitor 的目录结构可知,源码集中在 src 目录中.关于监控系统的迭代过程,可 ...