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;
}
总结
- HashMap可以存储键值对
- 初始容量是16,每次扩容2倍数
- 先添加,后扩容
- 从尾部添加
后续
里面代码确实挺多,其中还包括树,以后分析并尝试重写
相关文章:
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.va…...
Gin中用于追踪用户的状态的方法?!!!
Gin中的Cookie和Session的用法 文章目录 Gin中的Cookie和Session的用法介绍Cookie代码演示 Session代码展示 介绍 cookie 和 session 是 Web 开发中常用的两种技术,主要用于跟踪用户的状态信息。 Cookie func (c *Context) Cookie(name string, value string, max…...
HTTP代理与HTTPS代理在工作流程上有哪些区别
HTTP代理和HTTPS代理都是常见的代理技术,可以实现隐藏客户端IP地址、突破网络封锁、加速网站访问、过滤网络内容等功能。本文将介绍HTTP代理和HTTPS代理在工作流程上的区别。 HTTP代理的工作流程 客户端向代理服务器发送HTTP请求 当客户端需要访问某个网站时&#x…...

Docker从认识到实践再到底层原理(二-2)|Namespace+cgroups
前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…...
算法的概述
算法分析: 解决同一问题的算法可以有多种。 我们希望从中选出最优的算法,效率高或者存储空间小。为此,需要对算法进行评估,分析。 通常考虑两个度量: 1、 时间复杂度:算法运行时需要的总步数,…...

菜鸟教程《Python 3 教程》笔记(19):错误与异常
菜鸟教程《Python 3 教程》笔记(19) 19 错误和异常19.1 assert(断言)19.2 异常处理19.2.1 try/except19.2.2 try/except...else19.2.3 try-finally 语句 19.3 抛出异常19.4 用户自定义异常19.5 清理行为19.5.1 定义清理行为19.5.2…...

空气净化器上亚马逊美国站需要办理什么认证?空气净化器UL867测试报告如何办理?
空气净化器又称“空气清洁器”、空气清新机、净化器,是指能够吸附、分解或转化各种空气污染物(一般包括PM2.5、粉尘、花粉、异味、甲醛之类的装修污染、细菌、过敏原等),有效提高空气清洁度的产品,主要分为家用 、商用…...
SpringBoot的测试方案
写完代码后,测试是必不可少的步骤,现在来介绍一下基于SpringBoot的测试方法。 基于SpringBoot框架写完相应功能的Controller之后,然后就可以测试功能是否正常,本博客列举MockMvc和RestTemplate两种方式来测试。 准备代码 实体类…...
华为OD机考算法题:字符串解密
目录 题目部分 解读与分析 代码实现 题目部分 题目字符串解密题目说明给定两个字符串string1和string2。 string1是一个被加扰的字符串。string1由小写英文字母(a~z)和数字字符(0~9)组成,而加扰字符串由0~9、a~f 组…...

unity 锚点设置
锚点聚合情况: 一个2d物体的位置 pos x pos y 是中心点相对于锚点的偏移量: 中心点就是位置。 按住shift 锚点和中心点都会被设置: 按住Alt: 同时按住shift和alt : 中心点 锚点 UI元素在对应的位置上。 锚点拉伸情况…...

Hadoop:HDFS--分布式文件存储系统
目录 HDFS的基础架构 VMware虚拟机部署HDFS集群 HDFS集群启停命令 HDFS Shell操作 hadoop 命令体系: 创建文件夹 -mkdir 查看目录内容 -ls 上传文件到hdfs -put 查看HDFS文件内容 -cat 下载HDFS文件 -get 复制HDFS文件 -cp 追加数据到HDFS文件中 -appendTo…...

自定义封装异步任务组件,实现FutureTask功能
FutureTask 在 JDK1.8 后的异步编排API中的CompletableFuture,提供了 异步任务的成功回调、异常回调。 public class FutureTaskTest {public static void main(String[] args) throws Exception {CompletableFuture<String> future CompletableFuture.sup…...

【区块链 | IPFS】IPFS节点搭建、文件上传、节点存储空间设置、节点上传文件chunk设置
一、创建ipfs节点 通过ipfs init在本地计算机建立一个IPFS节点 本文有些命令已经执行过了,就没有重新初始化。部分图片拷贝自先前文档,具体信息应以实物为准 ipfs init initializing IPFS node at /Users/CHY/.ipfs generating 2048-bit RSA keypair.…...

【autodesk】浏览器中渲染rvt模型
使用Forge完成渲染 Forge是什么 为什么能够渲染出来rvt模型 Forge是由Autodesk开发的一套云端开发平台和工具集。在Forge平台中,有一个名为"Model Derivative"的服务,它可以将包括RVT(Revit)在内的多种BIM(…...

Python超入门(1)__迅速上手操作掌握Python
# 1.第一个代码:输出语句 # 1.第一个代码:输出语句 print("My dogs name is Huppy!") print(o----) print( ||| ) print("*" * 10) """ 输出结果: My dogs name is Huppy! o----||| ********** "&…...
后端面试话术集锦第 十四 篇:go语言面试话术
这是后端面试集锦第十四篇博文——go语言面试话术❗❗❗ 1. go数组、切片、扩容 go的数组和切片都是用来存储相同类型的数据集合。 数组是存储固定大小的集合,且为值引用。 但切片是存储无固定大小的集合,且为引用类型。 切片有三个属性,分别为指向指针的数组array,数组…...
Oralce集群管理-19C RAC 私有网络调整为BOND1
1 尝试在线添加私有网络的新接口 是否成功。 使用oifcfg命令在线添加新的网卡接口,在还没有配置bond1的条件下 也是可以添加成功的。 [gridorcldb1 ~]$ oifcfg getif eno3 192.168.224.0 global public ens3f0 10.2.0.0 global cluster_interconnect,asm eno…...
洛谷 Array 数论
题目: 对于长度为n的数组A,A中只包含从1到n的整数(可重复)。如果A单调不上升或单调不下降,A就可称为美丽的。 找出在长度为n时,有几个美丽的A。 思路: 这是一道数论题。 我们先找找“单调不递…...

简明SQL条件查询指南:掌握WHERE实现数据筛选
条件查询是用于从数据库中根据特定条件筛选数据行的一种方式,它避免了检索整个表中的数据。通常,使用 WHERE 子句来定义过滤条件,只有符合这些条件的数据行才会被返回。 SQL中的运算符有:、!、<、> 等,用于进行…...
通过HbaseClient来写Phoenix表实现
由于数据存储在Hbase上,并且上层使用了Phoenix来读写数据。并且由于数据的列字段不固定,并且可能由于Hbase表列和Phoenix的表列字段不一致,使用Phoenix写入的数据会导致写出报错的问题出现。所以这里直接使用HbaseClient写入到Hbase表中&…...

DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...

【Veristand】Veristand环境安装教程-Linux RT / Windows
首先声明,此教程是针对Simulink编译模型并导入Veristand中编写的,同时需要注意的是老用户编译可能用的是Veristand Model Framework,那个是历史版本,且NI不会再维护,新版本编译支持为VeriStand Model Generation Suppo…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...
深度解析云存储:概念、架构与应用实践
在数据爆炸式增长的时代,传统本地存储因容量限制、管理复杂等问题,已难以满足企业和个人的需求。云存储凭借灵活扩展、便捷访问等特性,成为数据存储领域的主流解决方案。从个人照片备份到企业核心数据管理,云存储正重塑数据存储与…...
RLHF vs RLVR:对齐学习中的两种强化方式详解
在语言模型对齐(alignment)中,强化学习(RL)是一种重要的策略。而其中两种典型形式——RLHF(Reinforcement Learning with Human Feedback) 与 RLVR(Reinforcement Learning with Ver…...
02-性能方案设计
需求分析与测试设计 根据具体的性能测试需求,确定测试类型,以及压测的模块(web/mysql/redis/系统整体)前期要与相关人员充分沟通,初步确定压测方案及具体的性能指标QA完成性能测试设计后,需产出测试方案文档发送邮件到项目组&…...