当前位置:首页 > 问答 > 正文

HashMap都讲了那么多遍了,怎么还有人不明白到底为啥这么用?

(来源:根据常见的程序员社区讨论、面试官反馈以及新手程序员的学习痛点综合整理)

“HashMap都讲了那么多遍了,怎么还有人不明白到底为啥这么用?”这话听起来是不是特别耳熟?可能你是那个恨铁不成钢的面试官或资深同事,也可能你是那个被问得一头雾水、心里嘀咕“我知道怎么用,但为啥非得是它”的新手,今天咱们不聊那些高深的源码,也不死磕那些术语,就掰开了揉碎了说说,在日常生活中,HashMap到底是个啥,以及我们为啥“非它不可”。

你可以把HashMap想象成一个超级有效率的“物品寄存处”或者“情报交换站”,想象一下这个场景:你去看一场大型演唱会,人山人海,入口处有一个寄存处,你需要把背包存起来,最笨的办法是什么?是你从001号柜子开始,一个一个试,看哪个是空的,然后把包塞进去,等你取包的时候,更痛苦,你得从001号开始,一个一个打开看,直到找到你的包,这效率,演唱会散场了你可能还没找到包,这就是如果没有HashMap,我们用一个大列表(List)存数据时的典型困境——查找全靠瞎蒙,速度慢得吓人。

HashMap都讲了那么多遍了,怎么还有人不明白到底为啥这么用?

那聪明的寄存处怎么做?它让你自己报出名字,比如你叫“张三”,服务员根据“张三”这个名字,通过一个特定的规则(比如计算名字笔划数,或者取首字母),瞬间就算出来你的包应该放在Z区的第3个柜子,你存的时候,他直接走到Z区第3个柜子放进去;你取的时候,他同样根据“张三”这个名字,瞬间定位到Z区第3个柜子,直接把包拿给你,这个“根据名字瞬间找到柜子”的魔法,就是HashMap的核心思想——“键值对”和“哈希计算”。

这里的“名字”(张三”),就是键(Key),那个“背包”,就是值(Value),而那个“根据名字算出来柜子位置”的规则,就是哈希函数(Hash Function),HashMap之所以快,就是因为它不是傻乎乎地挨个找,而是通过键(Key)这个“线索”,用哈希函数这个“计算公式”,直接算出值(Value)这个“物品”大概存放在哪个位置,然后直奔主题。

HashMap都讲了那么多遍了,怎么还有人不明白到底为啥这么用?

那为什么我们写程序时这么离不开它呢?因为它解决了我们编程中最常见、最头疼的一类问题:快速关联和快速查找

举个例子,你要做一个简单的用户管理系统,每个用户有一个唯一的ID(比如101,102,103)和对应的名字,如果你用一个List来存,你想找到ID为105的用户,程序不得不从第一个用户开始,问:“你是105吗?”“不是。”“你是105吗?”“不是。”……直到找到为止,用户少还好,如果有100万个用户,最坏情况下你得问100万次,慢得无法接受。

HashMap都讲了那么多遍了,怎么还有人不明白到底为啥这么用?

但如果你用HashMap,事情就简单多了,你把用户的ID作为Key,用户的所有信息(包括名字)打包成一个对象作为Value,存到HashMap里,当你想找ID为105的用户时,你只需要对105这个Key做一次哈希计算,就能直接定位到存储的大致位置,可能只需要一两次比较就能找到,这种速度上的差距,当数据量大的时候,是天壤之别,这就好比你在一个拥有百万个柜子的超级寄存处,用笨方法找包得找到天荒地老,而用HashMap的方法,几乎还是“秒取”。

再比如,统计一篇文章中每个单词出现的次数,你从头到尾读每个单词,遇到一个单词,apple”,你就去HashMap里查一下,Key就是“apple”,如果查不到,说明是第一次出现,你就存入(“apple”, 1),如果查到了,说明之前出现过,你就把对应的Value(当前次数)拿出来,加1,再存回去,这个操作非常自然和高效,因为HashMap帮你完美地维护了“单词”和“次数”之间的关联关系,如果你试图用List来做,代码会变得极其复杂和低效。

HashMap也不是完美的魔法,那个“计算公式”(哈希函数)有可能算出相同的结果,导致两个不同的Key(张三”和“张四”)被算到了同一个柜子位置,这就是所谓的“哈希冲突”,好的HashMap实现(比如Java里的)会有办法解决这个问题,比如在同一个柜子那里挂一个子清单(链表或红黑树),但这属于稍微进阶一点的话题,对于刚理解为什么要用HashMap的人来说,先知道它有聪明的办法解决冲突就够了。

回到最初的问题——“为啥非要用HashMap?”答案很简单:当你需要一种能通过一个“线索”(Key)快速找到另一个“东西”(Value)的时候,HashMap几乎就是你的首选工具。 它用空间(多占用一点内存来建立索引)换取了惊人的时间效率(查找速度极快),这种“键值对应”的需求在编程中无处不在:从缓存数据(Key是网址,Value是网页内容)、管理配置项(Key是配置名,Value是配置值),到数据库索引的底层原理,都能看到HashMap思想的影子。

明白了这一点,你就不会再死记硬背“HashMap允许null键null值,线程不安全”这些教条,而是能从心底里理解,在什么样的场景下,该毫不犹豫地选择它,它不是被神化的复杂技术,而是程序员为了解决实际痛点而创造出的、非常接地气的聪明工具,下次再用到它的时候,想想那个高效的“寄存处”,你可能就会会心一笑了。