当前位置: 首页 > news >正文

HashMap实现原理

HashMap是基于散列表的Map接口的实现。插入和查询的性能消耗是固定的。可以通过构造器设置容量负载因子,一调整容易得性能。

散列表:给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。HashMap中散列表由数组实现。

容量:散列表数组的长度。

负载因子:散列表中当前存储的项/容量。HashMap默认使用的负载因子是0.75。

HashMap是键-值对结构。HashMap的键不能重复(可以是null),而值可以重复。在Java中如果一个类作为HashMap的key要能正确的工作,那么这个类就需要同时实现hashCode()方法和equals()方法。

HashMap使用equals()判断当前键是否与表中存在的键相同。使用hashCode()生成散列码。hashCode()就是散列函数(也称为哈希函数)。

正确的equals()方法必须满足下列5个条件:

  • 自反性:对任意x,x.equals(x)一定返回true
  • 对称性:对任意x,y,如果x.equals(y)返回true,则y.equals(x)也返回true
  • 传递性:对任意x,y,z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也返回true
  • 一致性:对任意x,y,如果对象中用于等价等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致。
  • 对任何不是null的x,x.equlas(null)一定返回false

HashMap通过散列的方式决定如何存储以达到更快的查找速度。

首先看一下HashMap是如何表示一个键-值对的对象的。

Map.java

public interface Map<K, V> {interface Entry<K, V> {K getKey();V getValue();V setValue(V value);boolean equals(Object o);int hashCode();/// ......}/// ......
}

Map.java中定义了Entry<K, V>接口表示一个键-值对。具体的实现由Map的实现类定义。

HashMap.java

public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next;Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}public final K getKey()        { return key; }public final V getValue()      { return value; }public final String toString() { return key + "=" + value; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}public final boolean equals(Object o) {if (o == this)return true;return o instanceof Map.Entry<?, ?> e&& Objects.equals(key, e.getKey())&& Objects.equals(value, e.getValue());}}/// ......
}

HashMap基于散列表实现,在Java中使用一个数组表示散列表。通过散列将键信息(就是Map.Entry<K,V>对象)保存在数组中。散列通过键对象生成一个数字,将其作为数组的下标。这个数字就是散列码

在调用HashMap的put方法时,首先通过散列计算散列码得到数组的下标,然后查询指定下标的数组位置上是否有值(Map.Entry<K,V>),如果没有值则将put的键-值对生成Map.Entry<K,V>对象存在该位置。如果有值则对比当前put的值是否已经存在,如果存在则替换,不存在则将put的键-值对生成Map.Entry<K,V>对象添加到最后一个Map.Entry<K,V>next域上。

在调用HashMap的get方法时,同样先计算散列码得到数组的下标然后查询该位置的值,如果不存在则返回null,存则查找**Map.Entry<K,V>**链,直到找到对应键的值返回。

http://www.lryc.cn/news/61614.html

相关文章:

  • 【Java 数据结构】PriorityQueue(堆)的使用及源码分析
  • 使用 Kubernetes 运行 non-root .NET 容器
  • 为什么大量失业集中爆发在2023年?被裁?别怕!失业是跨越职场瓶颈的关键一步!对于牛逼的人,这是白捡N+1!...
  • Word控件Spire.Doc 【脚注】字体(3):将Doc转换为PDF时如何使用卸载的字体
  • keil5使用c++编写stm32控制程序
  • 中国社科院与美国杜兰大学金融管理硕士项目——在职读研的日子里藏着我们未来无限可能
  • hardhat 本地连接matemask钱包
  • 【华为OD机试真题】1001 - 在字符串中找出连续最长的数字串含-号(Java C++ Python JS)| 机试题+算法思路+考点+代码解析
  • CrackMapExec 域渗透工具使用
  • Modbus协议学习
  • camunda如何处理流程待办任务
  • git部分文件不想提交解决方案
  • 2023年全国最新道路运输从业人员精选真题及答案58
  • Zimbra 远程代码执行漏洞(CVE-2019-9670)漏洞分析
  • 【数据结构初阶】第七节.树和二叉树的性质
  • 车载软件架构——闲聊几句AUTOSAR BSW(一)
  • 我国元宇宙行业分析:政策、技术、资金助推行业探索多元化应用场景
  • 都已经那么卷了,用户还需要开源的 API 管理工具么
  • 工信部教育与考试中心-软件测试工程师考试题A卷-答
  • 【设计模式】模板方法模式--让你的代码更具灵活性与可扩展性
  • 搞明白Redis持久化机制
  • C# 中的正则表达式,如何使用正则表达式进行字符串匹配和替换?
  • 7年时间,从功能测试到测试开发月薪30K,有志者事竟成
  • ES6 块级作用域
  • ShardingSphere-JDBC垂直分片
  • Node 04-http模块
  • 记录项目过程中的编译错误及解决方法(持续更新中)
  • Android Hilt依赖注入框架
  • LeetCode:59. 螺旋矩阵 II
  • 信息安全复习六:公开密钥密码学