HashMap 源码解析

1. 基本结构

HashMap 的核心是一个数组,每个数组元素是一个链表或红黑树(JDK 1.8 及以后)。当哈希冲突发生时,链表或红黑树用于存储多个键值对。

// HashMap的基本结构
public class HashMap<K, V> extends AbstractMap<K, V>implements Map<K, V>, Cloneable, Serializable {// 默认初始容量为16static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16// 最大容量为2^30static final int MAXIMUM_CAPACITY = 1 << 30;// 默认加载因子为0.75static final float DEFAULT_LOAD_FACTOR = 0.75f;// 链表转化为红黑树的阈值static final int TREEIFY_THRESHOLD = 8;// 红黑树转化为链表的阈值static final int UNTREEIFY_THRESHOLD = 6;// 最小树化容量static final int MIN_TREEIFY_CAPACITY = 64;// 存储元素的数组transient Node<K, V>[] table;// 存储具体键值对的集合transient Set<Map.Entry<K, V>> entrySet;// 存储的键值对的数量transient int size;// 扩容和其他结构修改次数transient int modCount;// 阈值int threshold;// 加载因子final float loadFactor;// Node 是 HashMap 的基本结构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;if (o instanceof Map.Entry) {Map.Entry<?,?> e = (Map.Entry<?,?>)o;if (Objects.equals(key, e.getKey()) &&Objects.equals(value, e.getValue()))return true;}return false;}}// 其他重要的方法和类// ...
}
2. 哈希算法

HashMap 使用的哈希算法通过扰动函数减少哈希冲突,提高查找效率。

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

这个方法对键的哈希码进行高低16位混合,以增加随机性,减少冲突。

3. 初始化和扩容

HashMap 在插入元素时,会检查当前容量是否需要扩容,如果需要,就进行扩容。扩容时,新容量是旧容量的两倍。

// 初始化
public HashMap(int initialCapacity, float loadFactor) {if (initialCapacity < 0)throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);if (initialCapacity > MAXIMUM_CAPACITY)initialCapacity = MAXIMUM_CAPACITY;if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Illegal load factor: " + loadFactor);this.loadFactor = loadFactor;this.threshold = tableSizeFor(initialCapacity);
}// 扩容
final Node<K, V>[] resize() {Node<K, V>[] oldTable = table;int oldCap = (oldTable == null) ? 0 : oldTable.length;int oldThr = threshold;int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTable;}else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1; // double threshold}else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;else {               // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr == 0) {float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})Node<K, V>[] newTable = (Node<K, V>[])new Node[newCap];table = newTable;if (oldTable != null) {for (int j = 0; j < oldCap; ++j) {Node<K, V> e;if ((e = oldTable[j]) != null) {oldTable[j] = null;if (e.next == null)newTable[e.hash & (newCap - 1)] = e;else if (e instanceof TreeNode)((TreeNode<K, V>)e).split(this, newTable, j, oldCap);else { // preserve orderNode<K, V> loHead = null, loTail = null;Node<K, V> hiHead = null, hiTail = null;Node<K, V> next;do {next = e.next;if ((e.hash & oldCap) == 0) {if (loTail == null)loHead = e;elseloTail.next = e;loTail = e;}else {if (hiTail == null)hiHead = e;elsehiTail.next = e;hiTail = e;}} while ((e = next) != null);if (loTail != null) {loTail.next = null;newTable[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTable[j + oldCap] = hiHead;}}}}}return newTable;
}
4. 插入元素

插入元素时,首先计算元素的哈希值,然后确定存储位置。如果发生哈希冲突,将元素链入当前链表或红黑树中。

public V put(K key, V value) {return putVal(hash(key), key, value, false, true);
}final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {Node<K, V>[] tab; Node<K, V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K, V> e; K k;if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof TreeNode)e = ((TreeNode<K, V>)p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27575.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins三种构建类型

目录 传送门前言一、概念二、前置处理&#xff08;必做&#xff09;1、赋予777权限2、让jenkins用户拥有root用户的kill权限3、要运行jar包端口号需要大于1024 三、自由风格软件项目&#xff08;FreeStyle Project&#xff09;&#xff08;推荐&#xff09;三、Maven项目&#…

金融科技:推动保险行业数字化转型的引擎

随着科技的飞速发展&#xff0c;金融科技&#xff08;FinTech&#xff09;已经成为推动金融行业变革的重要力量。特别是在保险行业&#xff0c;金融科技正引领着一场深刻的数字化转型&#xff0c;为保险公司带来了前所未有的机遇与挑战。本文将探讨金融科技如何推动保险行业的数…

UDP 协议详解与实战

目录 简介什么是 UDP&#xff1f;UDP 与 TCP 的区别 UDP 数据传输方式单播 - Unicast&#xff08;1:1&#xff09;广播 - Broadcast&#xff08;1:n&#xff09;有限广播 - Limited Broadcast直接广播 - Directed Broadcast 组/多播 - Multicast&#xff08;n:m&#xff09;任播…

屹晶微EG3002 单通道功率MOSFET驱动芯片 贴片SOP8

EG3002作为一款功率MOSFET驱动芯片&#xff0c;它的应用领域主要取决于其技术参数和性能特点。根据之前提供的信息&#xff0c;EG3002可能适用于以下领域&#xff1a; 1. 电源管理&#xff1a;用于高效率电源转换器&#xff0c;如开关电源&#xff08;SMPS&#xff09;、电池充…

栈的实现详解

目录 1. 栈1.1 栈的概念及结构1.2 栈的实现方式1.3 栈的应用场景 2. 栈的实现2.1 结构体2.2 初始化2.3 销毁2.4 入栈2.5 出栈2.6 获取栈顶元素2.7 判空2.8 获取个数 3. test主函数4. Stack.c文件5. Stack.h文件6. 运行展示 1. 栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的…

基础排序算法详解与对比分析

排序算法是计算机科学中最基础和重要的算法之一。本文将详细介绍几种经典的排序算法&#xff0c;包括选择排序、插入排序、希尔排序、堆排序和归并排序&#xff0c;并进行代码实现和对比分析。 选择排序&#xff08;Selection Sort&#xff09; 选择排序的基本思想是每次从未…

Ubuntu修改MySQL的tmpdir参数失败的解决方法

问题 在查询大表时&#xff0c;MySQL提示ERROR 3 (HY000): Error writing file /tmp/MYfd268 (OS errno 28 - No space&#xff0c;应该是临时文件夹/tmp没有足够的空间&#xff1b;想修改文件夹/etc/mysql/my.cnf中的参数tmpdir命令改变临时文件夹&#xff1b; sudo nano /e…

《青少年编程与数学》课程方案:3、课程形式

《青少年编程与数学》课程方案&#xff1a;3、课程形式 一、这门课程是一门学习课程&#xff0c;不是教学课程二、这门课程是一门独立的课程&#xff0c;不是多门课程三、这门课程有一条主要的线索是计算四、这门课程需要重视输出、强调可见性五、这门课程需要灵活运用&#xf…

C/C++函数指针、C#委托是什么?

函数指针 #include<stdio.h>//声明函数指针 typedef int(*Calc)(int a, int b); int Add(int a, int b) {return a b; } int Sub(int a, int b) {return a - b; }int main() {Calc funcPoint1 &Add;Calc funcPoint2 &Sub;int x 120;int y 140;int z 0;z …

Docker 部署 RocketMQ

0. 拉取镜像 docker pull apache/rocketmq:5.2.0 docker pull styletang/rocketmq-console-ng1. 创建容器共享网络 docker network create rocketmq2. 启动NameServer # 启动 NameServer docker run -d --name rmqnamesrv -p 9876:9876 --network rocketmq apache/rocketmq:…

【YashanDB知识库】PHP使用OCI接口使用数据库绑定参数功能异常

【问题分类】驱动使用 【关键字】OCI、驱动使用、PHP 【问题描述】 PHP使用OCI8连接yashan数据库&#xff0c;使用绑定参数获取数据时&#xff0c;出现报错 如果使用PDO_OCI接口连接数据库&#xff0c;未弹出异常&#xff0c;但是无法正确获取数据 【问题原因分析】 开启O…

实例方法与静态方法

实例方法&#xff08;非静态方法&#xff09; 定义&#xff1a;实例方法是与类的实例&#xff08;对象&#xff09;相关联的方法。它们可以访问类的实例变量&#xff08;非静态变量&#xff09;&#xff0c;也可以访问类的静态变量和方法。 访问&#xff1a;实例方法必须通过类…

wangEditor富文本编辑器的调用开发实录(v5版本、多个编辑器、php后端上传视频阿里云OSS、编辑HTML回显)

wangEditor富文本编辑器的调用开发实录(v5版本、获取HTML内容、上传图片、隐藏上传视频)wangEditor富文本编辑器的调用开发实录2(V5版本自定义粘贴&#xff0c;去除复制word或网页html冗余样式代码的解决方案) wangEditor富文本编辑器的调用开发实录 一、多个编辑器1.构建HTML容…

张艺兴step新专开启自由驾驶新纪元

张艺兴《Step》新专&#xff0c;开启自由驾驶新纪元&#xff01;当音乐与驾驶相遇&#xff0c;会碰撞出怎样的火花&#xff1f;当实力派艺人张艺兴遇上全新英文专辑《Step》&#xff0c;便为我们解锁了一种前所未有的出行体验&#xff01;这不仅仅是一张音乐专辑&#xff0c;更…

Pandas AI:最棒的大模型数据分析神器!

暑期实习基本结束了&#xff0c;校招即将开启。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解惑答疑&…

MySQL中为什么要有隐式内连接和显式内连接

在MySQL多表联合查询中&#xff0c;区分隐式内连接&#xff08;Implicit Inner Join&#xff09;和显式内连接&#xff08;Explicit Inner Join&#xff09;的主要原因在于它们的语法风格、可读性、可维护性以及应用场景的差异。以下是对这两种连接方式的主要区别的详细分析&am…

Java Opencv识别图片上的虫子

最近有个需求&#xff0c;希望识别图片上的虫子&#xff0c;对于java来说&#xff0c;图像识别不是很好做。在网上也搜索了很多&#xff0c;很多的代码都是不完整&#xff0c;或者下载下载报错&#xff0c;有的写的很长看不懂。所以自己试着用java的opencv写了一段代码。发现识…

2024年计算机相关专业是否适合选择

2024年&#xff0c;计算机相关专业还值得选择吗&#xff1f; 随着2024年高考落幕&#xff0c;数百万高三学生又将面临人生中的重要抉择&#xff1a;选择大学专业。在这个关键节点&#xff0c;计算机相关专业是否仍是“万金油”的选择&#xff1f;在过去很长一段时间里&#xf…

Django+Vue.js怎么实现搜索功能

一.前言 类似这样的搜索功能 二.前端代码 <div class"form-container"><div class"form-group"><label for"departure-city">出发城市</label><select v-model"departureCity" id"departure-city&q…

把Vue项目从Window系统迁移到Mac系统的方案

不能启动vue ui 直接运行&#xff0c;会报错如下&#xff1a; failed to load config from /Users/xiaochen/IdeaProjects/ChatViewer-frontend/vite.config.tserror when starting dev server: Error: You installed esbuild for another platform than the one youre curre…