Java HashMap源码学习

Java HashMap源码学习

基本使用

包含创建,添加,删除,迭代,打印

val map = java.util.HashMap<Int, Int>()
map.put(1, 2)
map.put(2, 2)
map.put(3, 2)
map.remove(1)
map.forEach {println("it.key=${it.key}, it.value=${it.value}")
}
println(map)

分析源码

一贯原则,没用的帮兄弟们省掉了

简单介绍

package java.util;// AbstractMap,可以随机访问
public class HashMap<K, V> extends AbstractMap<K, V> {// 初始容量static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 最大容量static final int MAXIMUM_CAPACITY = 1 << 30;// 负载因子,当前容量超过最大容量*负载因子,开始扩容static final float DEFAULT_LOAD_FACTOR = 0.75f;// 链表大于8树化static final int TREEIFY_THRESHOLD = 8;// 树小于6链化static final int UNTREEIFY_THRESHOLD = 6;// 树化的最小容量static final int MIN_TREEIFY_CAPACITY = 64;// 存储key,valuestatic class Node<K, V> implements Map.Entry<K, V> {// 通过key中字段计算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;}// 省略get,set等模板方法}
}

创建

// 负载因子
public HashMap() {this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

添加

public V put(K key, V value) {// 通过hash()对key进行一次hash()return putVal(hash(key), key, value);
}// 重点分析
final V putVal(int hash, K key, V value) {// tab,桶,就是数组// p,期望对象// n,当前桶容量// i,桶下标Node<K,V>[] tab; Node<K,V> p; int n, i;// 如果是第一次,通过resize()更新初始容量if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 与桶大小&计算,二次hash()// 刚好桶上没元素,直接在桶上更新if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {// e,辅助期望元素// k,桶下标元素的keyNode<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)treeifyBin(tab, hash);break;}// 找到key一样的if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}e.value = value;}// 扩容if (++size > threshold)resize();return null;
}// key经过hashCode()与低位^,让高位也参与计算
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}// 二倍扩容
final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;// 当前容量int oldCap = (oldTab == null) ? 0 : oldTab.length;// 当前负载int oldThr = threshold;int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}// 二倍扩容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>[] newTab = (Node<K,V>[])new Node[newCap];table = newTab;if (oldTab != null) {// 遍历桶for (int j = 0; j < oldCap; ++j) {Node<K,V> e;if ((e = oldTab[j]) != null) {oldTab[j] = null;if (e.next == null)// 通过hash&新桶容量,计算位置newTab[e.hash & (newCap - 1)] = e;// 树转移else if (e instanceof TreeNode)((TreeNode<K,V>)e).split(this, newTab, j, oldCap);// 链表else { // preserve order// lo,low,hi,high,high=桶容量/2+lowNode<K,V> loHead = null, loTail = null;Node<K,V> hiHead = null, hiTail = null;Node<K,V> next;do {next = e.next;// 如果在下标0位置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;newTab[j] = loHead;}if (hiTail != null) {hiTail.next = null;newTab[j + oldCap] = hiHead;}}}}}return newTab;
}

总结

  1. HashMap可以存储键值对
  2. 初始容量是16,每次扩容2倍数
  3. 先添加,后扩容
  4. 从尾部添加

后续

里面代码确实挺多,其中还包括树,以后分析并尝试重写

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

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

相关文章

Cocos独立游戏开发框架中的日志模块:Bug无所遁形

引言 本系列是《8年主程手把手打造Cocos独立游戏开发框架》&#xff0c;欢迎大家关注分享收藏订阅。 在Cocos独立游戏开发框架中&#xff0c;一个强大的日志模块是不可或缺的组成部分。日志不仅仅是记录应用程序的运行状态&#xff0c;还可以用于故障排除、性能监测和安全审计…

26.篮球练习

题目 Description 小徐酷爱打篮球&#xff0c;在小学期的前两周半都在练习篮球。 今天&#xff0c;小徐想要练习如何突破。练习场地可由如下所示的网格图表示&#xff0c;图中的位置可用坐标表示。 其中A点(0,0)为小徐的起始位置&#xff0c;B点(n,m)为小徐想要到达的位置。…

高教社杯数模竞赛特辑论文篇-2018年D题:汽车总装线配置的优化模型研究

目录 摘 要 1. 问题的重述 1.1 装配要求 1.2 喷涂要求 1.3 需要解决的问题 2. 问

python中如何使用正则表达匹配\本身?(文末赠书)

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 将军向宠&#xff0c;性行淑均。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python钻石群【空】问了一个Python正则表达式的问题&#xff0c;一起…

PageHelper分页原理解析

大家好&#xff0c;我是Leo! 今天给大家带来的是关于PageHelper原理的解析&#xff0c;最近遇到一个SQL优化的问题&#xff0c;顺便研究了一下PageHelper的原理&#xff0c;毕竟也是比较常用&#xff0c;源码也比较好看的懂&#xff0c;如果感兴趣的小伙伴可以跟着过程去DEBUG源…

tcp字节传输(java)-自定义包头和数据识别

1、背景 tcp传输的时候会自动拆包&#xff0c;因此服务端接收的数据段可能跟客户端发送过来的数据段长度不一致&#xff0c;比如客户端一次发送10000个字节。但是服务端接收了两次才接收完整&#xff08;例如第一次接收6000字节&#xff0c;第二次接收4000字节&#xff09;。但…

vue3 watch watchEffect

watch & watchEffect 函数都是监听器, 用于监视数据的变化; watch 有惰性&#xff0c;watchEffect 无惰性&#xff1b;watch 需要指定具体的监视属性&#xff0c;watchEffect 不需要指定具体的监视属性和配置参数&#xff0c;会自动感知代码依赖&#xff1b;watch 能获取到…

【Web_接口测试_Python3_日期时间库】Arrow获取过去/当前未来时间日期、格式化时间日期、转换时间戳、获取不同时区时间日期等

## 简介 Arrow是一个 Python 库&#xff0c;它提供了一种明智且人性化的方法来创建、操作、格式化和转换日期、时间和时间戳。它实现并更新 datetime 类型&#xff0c;填补了功能上的空白&#xff0c;并提供了支持许多常见创建方案的智能模块 API。简而言之&#xff0c;它可以帮…

AI云服务平台大全:GPU租用 | App托管 | MLOps平台

我们搜集整理了国内外主要的深度学习云服务商&#xff0c;包括云GPU供应商、WebApp托管商和MLOps平台商。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 1、云GPU供应商 只有一台笔记本电脑&#x1f4bb;不足以运行你的AI模型&#xff0c;忘记它吧&#xff0c;使用云 …

解密Spring Cloud Alibaba核心技术,实战案例书现世

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作者&#x1f3c6;&#xff0c;阿里云专家博主&#x1f3…

晨启,MSP430开发板,51开发板,原理图,PCB图

下载&#xff1a;https://github.com/xddun/blog_code_search

【算法训练-链表 五】【求和】:链表相加(逆序)、链表相加II(顺序)

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【链表相加】&#xff0c;使用【链表】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&…

【unity3D】如何修改相机的默认视角

&#x1f497; 未来的游戏开发程序媛&#xff0c;现在的努力学习菜鸡 &#x1f4a6;本专栏是我关于游戏开发的学习笔记 &#x1f236;本篇是unity的如何修改相机的默认视角 如何修改相机的默认视角 Game窗口运行的话视角是这样的&#xff1a; 此时Scene窗口的视角是这样的&…

java基础面试题第二天

1.java基础面试题第三天 1.数组到底是不是对象 是对象。 先说说对象的概念。对象是根据某个类创建出来的一个实例&#xff0c;表示某类事物中一个具体的个体。数组类的父类就是Object类&#xff0c;那么可以推断出数组就是对象。 2.java的基本数据类型有哪些&#xff1f; b…

[华为云云服务器评测] 华为云耀云服务器 Java、node环境配置

系列文章目录 第一章 [linux实战] 华为云耀云服务器L实例 Java、node环境配置 文章目录 系列文章目录前言一、任务拆解二、修改密码三、配置安全规则四、远程登录并更新apt五、安装、配置JDK环境5.1、安装openjdk,选择8版本5.2、检查jdk配置 六、安装、配置git6.1、安装git6.2…

Git版本管理

Git版本介绍 Git 是一个分布式版本控制系统&#xff0c;它被广泛用于协作软件开发和管理代码的变更。Git 的设计目标是为了处理速度快、灵活性强、数据完整性好的版本管理需求。以下是 Git 版本管理的详细介绍&#xff1a; 版本控制系统 (VCS)&#xff1a; Git 是一种版本控制…

Centos7.6离线安装docker

一、Docker安装 1、安装环境&#xff1a; 系 统&#xff1a;CentOS Linux release 7.6.1810 (Core) Docker版本&#xff1a;19.03.5 2、下载离线安装包 docker安装包下载&#xff1a;https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker…

湖南省副省长秦国文一行调研考察亚信科技

9月5日&#xff0c;湖南省人民政府党组成员、副省长秦国文一行到亚信科技调研考察&#xff0c;亚信科技高级副总裁陈武主持接待。 图&#xff1a;双方合影 在亚信科技创新展示中心&#xff0c;秦国文了解了亚信科技在5G、算力网络、人工智能、大数据等前沿领域的创新探索&…

Ubuntu开放指定端口

在Ubuntu中&#xff0c;要开放特定的端口&#xff0c;通常涉及到两个步骤&#xff1a; 配置服务&#xff1a;确保您的服务或应用程序正确配置为监听所需的端口。 更新防火墙规则&#xff1a;如果您使用的是防火墙&#xff08;例如ufw&#xff0c;它是Ubuntu的默认防火墙工具&a…

冠达管理:股票退市整理期?

近些年来&#xff0c;随着我国股市的发展&#xff0c;股票市场的出资者逐渐增多。但在出资过程中&#xff0c;退市股票的问题也成为了备受重视的论题。那么&#xff0c;股票退市收拾期到底是什么&#xff1f;如何应对退市股票&#xff1f; 首要&#xff0c;什么是股票退市收拾…