HashMap底层详解
1. HashMap的数据结构
数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。
数组
数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;
链表
链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。
哈希表
那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。哈希表((Hash table)既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便。
哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法—— 拉链法,我们可以理解为“链表的数组” ,如图:
从上图我们可以发现哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。
HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?这里HashMap有做一些处理。
首先HashMap里面实现一个静态内部类Entry,其重要的属性有 key , value, next,从属性key,value我们就能很明显的看出来Entry就是HashMap键值对实现的一个基础bean,我们上面说到HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。
transient Entry[] table;
2. HashMap的存取实现
既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现:
int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值
int index = hash % Entry[].length;
Entry[index] = value;
// 取值时:
int hash = key.hashCode();
int index = hash % Entry[].length;
return Entry[index];
1)put
这里HashMap里面用到链式数据结构的一个概念。上面我们提到过Entry类里面有一个next属性,作用是指向下一个Entry。打个比方, 第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。所以疑问不用担心。也就是说数组中存储的是最后插入的元素。到这里为止,HashMap的大致实现,我们应该已经清楚了。
}
当然HashMap里面也包含一些优化方面的实现,这里也说一下。比如:Entry[]的长度一定后,随着map里面数据的越来越长,这样同一个index的链就会很长,会不会影响性能?HashMap里面设置一个因子,随着map的size越来越大,Entry[]会以一定的规则加长长度。
2)get
3)null key的存取
null key总是存放在Entry[]数组的第一个元素。
}
4)确定数组index:hashcode % table.length取模
HashMap存取时,都需要计算当前key应该对应Entry[]数组哪个元素,即计算数组下标;算法如下:
5)table初始大小
注意table初始大小并不是构造函数中的initialCapacity!!
而是 >= initialCapacity的2的n次幂!!!!
————为什么这么设计呢?——
3. 解决hash冲突的办法
- 开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
- 再哈希法
- 链地址法
- 建立一个公共溢出区
Java中hashmap的解决办法就是采用的链地址法。
4. 再散列rehash过程
当哈希表的容量超过默认容量时,必须调整table的大小。当容量已经达到最大可能值时,那么该方法就将容量调整到Integer.MAX_VALUE返回,这时,需要创建一张新表,将原表的映射到新表中。
}
}
HashMap底层详解相关推荐
- 【Java基础】HashMap原理详解
[Java基础]HashMap原理详解 HashMap的实现 1. 数组 2.线性链表 3.红黑树 3.1概述 3.2性质 4.HashMap扩容死锁 5. BATJ一线大厂技术栈 HashMap的实 ...
- Redis五种基本数据类型底层详解(原理篇)
Redis五种基本数据类型底层详解 详细介绍Redis用到的数据结构 简单动态字符串 SDS和C字符串的区别 总结 链表 字典 哈希表 字典 哈希算法 解决键冲突 rehash(重点) 渐进式reha ...
- HashMap原理详解(基于jdk1.8)
HashMap原理详解(基于jdk1.8) HashMap原理详解,有兴趣的同学可以看下.有错误的地方也希望大佬们能指点下. HashMap的内部存储是一个数组(bucket),数组的元素Node实现 ...
- ConcurrentHashMap底层详解(图解扩容)(JDK1.8)
数据结构 使用数组+链表+红黑树来实现,利用 CAS + synchronized 来保证并发更新的安全 源码分析 put方法 public V put(K key, V value) {return ...
- HashMap 原理详解
一.HashMap的原理详解 首先我们要知道什么是哈希表以及它的结构.在介绍哈希表之前我们需要了解并且掌握数组.链表以及红黑树的结构以及特点. 1.我们先来看一下HashMap的使用 public c ...
- iOS runtime 底层详解、内部原理、场景应用
前言学:位域和共用体 一:isa指针--runtime之前的学习 1.1:苹果应用的按位或.按位与 二:类对象信息 2.1:类对象信息:rw_t 2.2:类对象信息:方法缓存(很关键) 2.2:类对象 ...
- Java集合篇:HashMap原理详解(JDK1.8)
概述 JDK 1.8对HashMap进行了比较大的优化,底层实现由之前的"数组+链表"改为"数组+链表+红黑树",本文就HashMap的几个常用的重要方法和JD ...
- Java集合篇:HashMap原理详解(JDK1.7及之前的版本)
(本文有关HashMap的源码都是基于JDK1.6的) 摘要: HashMap是Map族中最为常用的一种,也是 Java Collection Framework 的重要成员.本文首先给出了 Hash ...
- hashmap扩容机制_图文并茂:HashMap经典详解!
点击上方 Java后端,选择 设为星标 优质文章,及时送达 代码中的注解多看几遍,其中HashMap的扩容机制是要必懂知识!结合图片一起理解! 什么是 HashMap? HashMap 是基于哈希表的 ...
最新文章
- 【C#实践】详解三层转七层:登录
- java 图片传输方式_Java图像传输方法
- php mysql_query的的用法_PHP / MYSQL使用mysqli_query选择
- pac (PAC(Proxy Auto Config) 是一个 Script;经由编写这个 Script,我们可以让系统判断在怎么样的情形下,要利用哪一台 Proxy 来进行联机。)...
- Error:java: 无效的目标发行版: 11解决方案
- 华为鸿蒙osbeta在哪看发布会,重磅消息!华为在发布鸿蒙OS2.0手机beta版本后,又发布搭载鸿蒙的新品!!...
- 大数据应用之金融行业-互联网金融对传统银行业的冲击,狼真的来了
- 蚂蚁资深算法专家周俊:从原理到落地,支付宝如何打造保护隐私的共享智能?...
- go int 转string_go 变量传递和切片
- Asp.net源码上周更新目录(5.12-5.18)
- 学习SQL 的网址集合
- 电子计算机专业vs土木工程专业,最难学十大工科专业 不想累成狗就别去(高薪)...
- python基础篇--变量和简单的数据类型(上)
- oracle 查询default,oracle分区表检查--是否带有max或default分区
- html页面上显示拼音
- 游戏必备组件_电脑必备软件~强大到~ 相识恨晚的感觉
- H3CSE20200603班-SSL V*N
- linux小红帽系统改时间,怎样更改linux小红帽系统时区由mst改成cst
- ubuntu11.10安装sopcast
- sphinx(附demo)
热门文章
- 一份来自蚂蚁金服大佬的数据库设计总结(纯干货)
- 小新padpro2021实体键盘快捷键备忘
- 企业各职位英文缩写 PM,TM,PL,TL,SE,PG,CEO,CFO
- LibreCAD for windows 编译
- 导航栏: UINavigationBar用法
- android 微信签名,Android微信签名知识的总结
- fiddler 不同版本功能说明
- ENVI|一天一个小技能|APP STORE浏览并下载矢量数据
- Mac系统随笔 | (1)Mac系统中的PageUp、PageDown、Home和End
- QImage 大小缩放