当前位置: 首页 > 编程日记 > 正文

HashMap总结

为什么用HashMap

  • HashMap是一个Hash桶(数组+链表),桶存储的内容是键值对(Key-value)映射
  • HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和链表的寻址修改
  • HashMap是非synchronized,所以HashMap很快(哈哈哈)

与HashTable的区别?

HashTable:线程安全,效率低,不允许Null键Null值

HashMap:非线程安全,效率高,允许Null键Null值存储

为什么HashMap允许为空 Hashtable不允许为空

Hashtable中put时如果Value为空,会引出空指针异常

而Key为空时,在调用hashCode()时,也会报空指针

以下是Hashtable put方法片段

if (value == null) {throw new NullPointerException();
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
复制代码

而HashMap的没有对value进行空判断,而且hashMap内部实现的hash()方法,当key为null时,返回0

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
复制代码

HashMap工作原理是什么?

HashMap是基于hashing的原理,储对象通过使用put(key, value)存到hash桶中,获取对象通过get(key)从hash桶中检索。
HashMap通常会用一个Hash桶(table[])来做分散所有的key,当一个key被加入时,会通过Hash算法通过key算出对应这个数组的下标i,然后就把该键值对插到table[ i ]中,如果有两个不同的key被算在了同一个i下标,那么就叫Hash冲突,又叫 Hash碰撞,那么在同一个位子上的元素将以链表的形式存放,先加入的在链头,后加入的放在链尾,这样会在table[i]上形成一个链表。最坏的情况下,所有的key都映射到同一个下标位置,这样hashmap就退化成了一个链表——查找时间从O(1)到O(n)
Hash表这个容器当有数据要插入时,都会检查容量有没有超过当前的threshold(阈值),如果超过,则扩容,但是这样,整个Hash桶里元素需要重新算一遍新的位置。这叫rehash,这个成本相当的大,因此《码出高效》中也推荐在集合创建时,可以根据实际情况,指定集合初始值大小。

put()实现

当我们给put(K,V)方法传递键和值时,我们先对键(Key)调用hashCode()方法,返回的hashCode用于找到bucket位置(Hash桶数组下标)来储存对象。

探索源码:HashMap底层put探索

get()实现

当调用get(K)获取value时,我们也会先对键(K)调用hashCode()方法,返回的hashCode用于找到bucket位置中的Entry对象,相当于索引,他的时间复杂度是O(1)

探索源码:HashMap底层get探索

resize() / 扩容实现 / rehash

当发生哈希冲突并且size大于阈值的时候,需要进行数组扩容,扩容时,需要新建一个长度为之前数组2倍长度的新的数组,然后将当前的Entry数组中的元素全部传输过去,扩容后的新数组长度为之前的2倍,扩容相对来说是个耗资源的操作

探索源码:HashMap底层扩容实现

Hash碰撞

再说Hash碰撞之前,先了解一下hashCode()和equals()两个方法的区别

// hashCode()返回值相同的两个对象 两个对象equals()结果不一定为true
// equals()结果为true的两个对象,hashcode()返回值一定相同
复制代码

明明两个Key是不同的,但hashCode相同,导致的Hash碰撞(Hash冲突),hashCode是存储地址索引,如果该地址已经存在对象元素了,是返回错误,还是覆盖现有对象元素呢?在Java中,这时候链表结构就有意义了,单链表的头指针存在Hash桶的(hashCode索引下标)对应位置中,但此时检索的时间复杂度也变成了O(n)

Hash碰撞解决方法

为什么String, Interger这样的封装类适合作为键?

  • String,Interger这些封装类内部的值都是不可变的(final关键字修饰),

  • 并且内部重写了equals()和hashCode()方法,其他的封装类也有这个特点,因为存取对象的时候要用到equals()和hashCode()方法。

  • 不可变性是必要的,为了计算hashCode(),就要防止键值改变,否则检索就没有意义了。

  • 不可变性还有其他的优点如线程安全

为什么HashMap的桶数组长度一定是2的次幂?

HashMap内部定义了每次扩容是原本长度的两倍,也就是每次扩容,左移一位,那么这样做的的好处呢?

合理存放元素

桶长度为16扩容后变成32,(二进制)10000-->100000

(length-1) 也从 1111 变成 11111 # 对于什么是length-1请先看完源码

2的n次方就是1后面n个0,2的n次方-1 实际就是n个1;

h&1111 和 h&11111

假设h为21(10101)

我们会发现, 因为'0 1111'低位都是'1', 进行'&'(位与)操作, 就能成功保留'10101'对应的低位, 将高位的都丢弃, 低位是多少, 最后结果就是多少 . 刚好低位的范围是'0~15', 刚好是长度为16的所有索引 ,扩容后也是同理

均匀分布,减少碰撞

例如长度为9时候,3&(9-1) = 0 ; 2&(9-1) = 0,那么索引位置都在0上,发生碰撞

例如长度为8时候,3&(8-1)=3 ; 2&(8-1)=2 ,元素均匀存入不同位置上

总结

所以hash桶数组长度为2次幂,是为了能够合理放入有效数组索引中以及防止hash发生太多碰撞,对于HashMap检索是有利的

参考文档

How HashMap works in Java

HashMap实现原理及源码分析

转载于:https://juejin.im/post/5d47e7e3f265da03986bd7cf

相关文章:

Blender与Substance painter制作三维手枪

你会学到: Blender和Substance painter的基础知识 建模 纹理制作 烘焙 Uv展开 Boolens和斜角修改器 如何制作游戏准备枪 课程获取&#xff1a;Blender与Substance painter制作三维手枪 – 云桥网络-CG技术学习平台 要求 Blender Substance painter 你好&#xff0c;我是3d艺术…

Java学习总结:32(Runtime类)

Runtime类 该类用于表示虚拟机(JVM)运行时的状态&#xff0c;每次启动JVM都对应一个Runtime实例&#xff0c;且只有一个实例&#xff0c;利用Runtime类可以启动新的进程或进行相关运行时环境的操作。此外&#xff0c;该类采用单例模式设计&#xff0c;对象不可以直接实例化。所…

转:查看系统是64位还是32位

1、getconf LONG_BIT or getconf WORD_BIT 例如&#xff1a; 2、file /bin/ls 例如&#xff1a; 查看linux的版本: 转载于:https://www.cnblogs.com/lei-lei/p/5029120.html

Redis问题——Error: 磁盘在使用中,或被另一个进程锁定。

Redis出于对数据保护&#xff0c;默认只能本地客户端连接。远程连接就会出现以上错误。如何解决这一问题&#xff0c;看下&#xff1a; server -A&#xff0c;PC-A&#xff0c; 修改server-A的redis.conf:注释掉本地绑定&#xff1b; bind 127.0.0.1 表示指定绑定本机IP&…

[转]C#索引器

索引器是一种特殊的类成员&#xff0c;它能够让对象以类似数组的方式来存取&#xff0c;使程序看起来更为直观&#xff0c;更容易编写。 1、索引器的定义 C#中的类成员可以是任意类型&#xff0c;包括数组和集合。当一个类包含了数组和集合成员时&#xff0c;索引器将大大简化对…

从Java8到Java21各版本新特性详解

​ 下面这张图是 Oracle 官方给出的 Oracle JDK 支持的时间线,可以看出,JDK 17的支持时间最长,可以延续到2029年9月。考虑到技术更新的速度,这次免费商用8年的时间可谓是经过精心考虑,旨在让用户放心地升级到JDK 17(不过JDK 8的支持时间更长,到2030年12月)。​ 从JDK诞生到现在,仅有几个版本得到了长期支持,主要包括JDK 7、JDK 8、JDK 11以及即将发布的JDK 17,它将是继Java 8之后最重要的LTS版本,是Java社区八年努力的成果。

make[1]: g++: Command not found

今天装了nmap软件&#xff0c;开始报这种错&#xff1a;g -c -Iliblua -Ilibdnet-stripped/include -Ilibpcre -Ilibpcap -Inbase -Insock/include -fno-strict-aliasing -DHAVE_CONFIG_H -DNMAP_NAME\"Nmap\" -DNMAP_URL\"http://nmap.org\" -DNMAP_PL…

学习如何用平板电脑设计和绘制自己的动漫角色

创造你自己的动漫人物插图 学习如何用平板电脑设计和绘制自己的动漫角色 大家好&#xff0c;我是Pesa&#xff0c;一个想把快乐和希望融入到讲述故事的插画中的插画师。一点一点地&#xff0c;我画出我喜欢和希望的事物的场景&#xff0c;它把我带到了101班。 艺术世界 艺术是…

Java学习总结:33(System类)

System类 System类的方法 No.方法类型描述1public static void arraycopy(Object src&#xff0c;int srcPos&#xff0c;Object dest&#xff0c;int destPos&#xff0c;int length)普通数组粘贴操作2public static long currentTimeMillis()普通取得当前的日期时间&#x…

重磅推出:AutoProject Studio 自动化项目生成器

AutoProject Studio 自动化项目生成器 核心架构图 AutoProject Studio 自动化项目生成器是一款基于C#.Net Framework 4.0为平台自主研发、专为软件设计、开发、管理的自动化项目(代码)生成器&#xff0c;同时也是一个智能化软件开发平台与超高效率、超低成本的最优解决方案。 该…

2022-2028年中国基因工程药物产业市场研究及前瞻分析报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国基因工程药物行业市场行业相关概述、中国基因工程药物行业市场行业运行环境、分析了中国基…

Perl 模块安装遇到的问题解决办法

2019独角兽企业重金招聘Python工程师标准>>> 问题1&#xff1a;Warning (usually harmless): YAML not installed, will not store persistent state 解决办法&#xff1a; 官网下载&#xff1a;http://search.cpan.org/~mstrout/YAML-0.84/lib/YAML.pm 上传安装…

如何终止一个正在动态执行的命令

比如&#xff0c;我们在终端输入了top 那么它就会一直动态的运行下去。 我们怎样让它终止呢&#xff1f; 很简单&#xff0c;Ctrl C就可以了。 另外&#xff0c;还有一种方法&#xff0c; 直接按一下q也可以退出。 它们两个的效果是一样的。转载于:https://www.cnblogs.com/o8l…

绘制你的世界:探索构图和真实的深度感

MP4 |视频:h264&#xff0c;1920 x 1080 |音频:AAC&#xff0c;48 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&#xff08;根据原英文字幕机译更准确&#xff09;| 2h 24m |大小解压后:3.2 GB 勾画你的世界不是关于天赋&#xff0c;而是关于任何人都可以学习的原则和…

Java学习总结:34(对象克隆)

对象克隆 对象克隆就是对对象的复制操作&#xff0c;在Object类中存在一个clone()方法用于对象的克隆操作。该方法如下&#xff1a; protected Object clone() throws CloneNotSupportedException&#xff1b;我们注意到&#xff1a; 1.此方法使用了protected访问权限&#x…

win7下的IP-主机名映射

今天学了个技巧&#xff0c;win7下有个目录&#xff1a;C:\Windows\System32\drivers\etc该目录下有个文件&#xff1a;hosts在这个文件里面我们可以映射IP-主机名&#xff1a;127.0.0.1 localhost........格式为&#xff1a;IP空格主机名这样我们就可以用主机名代替IP了。转载…

Spring AOP + Redis解决重复提交的问题

Spring AOP Redis解决重复提交的问题 用户在点击操作的时候&#xff0c;可能会连续点击多次&#xff0c;虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击&#xff0c;但是如果别人拿到请求进行模拟&#xff0c;依然会出现问题&#xff0c;项目是用JWT进行认证…

转:Flash 插件面板 DragonBonesDesignPanel 的绿色安装方法

最近在cocos2d-js下捣腾Dragonbones。转一个文章&#xff0c;大家可以参考安装Dragonbones。关于这个Dragonbones&#xff0c;5月份的时候还用得好好的&#xff0c;cocos2d-js还能妥妥的加载。最近就不行了&#xff0c;原来默默的升级了。还是得找回原来的2.0版本&#xff0c;后…

任务18:控制反转

控制反转 实现你的依赖&#xff0c;采用什么依赖&#xff0c;不由你自己决定&#xff0c;这个控制交给IOC容器。 这里所有的实现都不由你自己决定&#xff0c;我们只需要传给你就可以了。谁来传呢&#xff1f;容器来传给他 内存的Repository&#xff0c;这里实现的比较简单。 这…

Quixel megascans模型材质贴图合集包

Quixel megascans是一个在线高分辨率扫描模型和贴图库&#xff0c;一致的PBR校准的表面&#xff0c;植被&#xff0c;和三维扫描模型&#xff0c;还包括用于管理的桌面应用、混合和输出你的扫描数据的程序。它的产品已经与游戏和电影工作室合作。 quixel megascans可以帮助您创…

Java学习总结:35(数字操作类)

Java的数字操作类 一.Math类 Math类是一个专门用来进行数学计算的操作类&#xff0c;它提供了一系列的数学计算方法。在Math类里面提供的一切方法都是static型方法&#xff0c;所以可以直接由类名称进行调用。 例&#xff1a;观察四舍五入操作 package Project.Study.MathC…

STL笔记(5)条款49:学习破解有关STL的编译器诊断信息

STL笔记&#xff08;5&#xff09;条款49&#xff1a;学习破解有关STL的编译器诊断信息 条款49&#xff1a;学习破解有关STL的编译器诊断信息 用一个特定的大小定义一个vector是完全合法的&#xff0c; vector<int> v(10); // 建立一个大小为10的vector而string在很多…

执子之手,与子偕老。你同意么?

(1):5岁的时候&#xff0c;我说我爱你。你歪着脑袋&#xff0c;眨着水晶般的大眼睛&#xff0c;疑惑地问我&#xff1a;“什么意思呀&#xff1f;” (2):15岁的时候&#xff0c;我说:"我爱你".你的脸红得像火烧云&#xff0c;头深深地低着&#xff0c;摆弄著衣襟&…

34种墨西哥植物模型 Globe Plants – Bundle 34 Mexican Plants

Globe Plants Bundle 34墨西哥植物(3D模型)包括15种3D树木、灌木和肉质植物&#xff0c;用于南美洲的风景、住宅、花园和一般景观美化目的&#xff0c;特别是墨西哥&#xff0c;具有85种独特的照片逼真质量的3D植物模型&#xff0c;具有多种形式&#xff0c;可用于您的许多场景…

Java学习总结:36(日期处理类)

日期处理类 Date类 Date类常用方法 No.方法类型描述1public Date()构造实例化Date类对象2public Date(long date)构造将数字变为Date类对象&#xff0c;long为日期时间数据3public long getTime()普通将当前的日期时间变为long型 例&#xff1a;取得当前的日期时间 package…

最强的篮球队和马尔可夫模型

打篮球经常遇到这种情况&#xff0c;11个人&#xff0c;分4、4、3共三套&#xff0c;一群人少时间玩&#xff0c;在一个失败的团队的人下阵来填补空缺。因此&#xff0c;我认为&#xff0c;&#xff0c;会不会出现一个最强组合&#xff0c;使得这4个人一直赢比赛呢&#xff1f;…

1677: [Usaco2005 Jan]Sumsets 求和

1677: [Usaco2005 Jan]Sumsets 求和 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 626 Solved: 348[Submit][Status]Description Farmer John commanded his cows to search for different sets of numbers that sum to a given number. The cows use only numbers that ar…

通过CPAN安装Perl模块

第一步&#xff0c;进入CPAN shell&#xff1a; sudo perl -MCPAN -e shell 第一次运行会问你一些问题&#xff0c;一般来说缺省答案就好 第二步&#xff0c;执行安装程序&#xff0c;例如安装LWP:UserAgent cpan>install LWP:UserAgent 还有一个二合一的命令&#xff0c;效…

Python3和Raspberry Pi最全面最直接的课程

在一门课程中学习Python 3基础知识、高级Python、科学Python、Raspberry Pi、硬件和物联网项目 教程获取&#xff1a;Python3和Raspberry Pi最全面最直接的课程 – 云桥网络-CG技术学习平台 你会学到: Python 3基础 Python 3高级概念 Raspberry Pi的设置和使用 Scientific Py…

Java学习总结:37(比较器)

比较器 Arrays类 No.方法类型描述1public static boolean equals(int [] a,int [] a2)普通判断两个数组是否相等&#xff0c;此方法被重载多次&#xff0c;可以判断各种数据类型的数组2public static void fill(int [] a,int val)普通将指定内容填充到数组中&#xff0c;此方…