HashMap的tableSizeFor方法解析

2024-06-01 12:58

本文主要是介绍HashMap的tableSizeFor方法解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

HashMap的源码有点小复杂,一次性没办法全部弄懂,所以分多次去理解,看懂一点就记录一点,最后再来写个汇总篇,这里先记录其中的tableSizeFor方法。另外jdk版本是1.8.

上代码

    /*** Returns a power of two size for the given target capacity.*/static final int tableSizeFor(int cap) {int n = cap - 1;n |= n >>> 1;n |= n >>> 2;n |= n >>> 4;n |= n >>> 8;n |= n >>> 16;return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;}

看英文注释大概也知道是什么意思了,返回目标容量对应的2的幂次方大小,举个栗子:
5到8都返回8,9到16都返回16,明白了吧;
那为什么hashMap的数组长度总是要2的幂次方大小呢?
这里简单说下,HashMap在存数据时,是根据key的hash值(实际还做了扰乱处理)与数组长度-1(2的n次幂-1后二进制低位全是1)进行&运算确定数组的位置,全是1能够保证数据均匀分布,如果有一些位置为0,对应的一些数组位置永远都不会有数据,文字面描述的比较抽象,不明白的可以自己动手试一试,这是另外一个话题,这里不多说。

代码解析

找一个数据来走一遍这段代码,例如2^29 + 1,对应的二进制是:00100000000000000000000000000001
第一步:int n = cap - 1;
n:00100000000000000000000000000000
第二步:n |= n >>> 1;

00100000000000000000000000000000
|
00010000000000000000000000000000
=
00110000000000000000000000000000

第三步:n |= n >>> 2;

00110000000000000000000000000000
|
00001100000000000000000000000000
=
00111100000000000000000000000000

第四步:n |= n >>> 4;

00111100000000000000000000000000
|
00000011110000000000000000000000
=
00111111110000000000000000000000

第五步:n |= n >>> 8;

00111111110000000000000000000000
|
00000000001111111100000000000000
=
00111111111111111100000000000000

第六步:n |= n >>> 16;

00111111111111111100000000000000
|
00000000000000000011111111111111
=
00111111111111111111111111111111

第六步:return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;

00111111111111111111111111111111
+
00000000000000000000000000000001
=
01000000000000000000000000000000

最终2^29 + 1得到的结果为2^30,符合我们最初的判断。观察数据我们发现其实这一段代码的逻辑分三个部分,先减一,再将得到的数的二进制数从1开始全部变成1,最后再加一,最终得到的数总是2的n次幂;你可以再拿个小数再走一遍流程,会让你更加清晰,我这里就不再做了。

这篇关于HashMap的tableSizeFor方法解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1021073

相关文章

CentOS7增加Swap空间的两种方法

《CentOS7增加Swap空间的两种方法》当服务器物理内存不足时,增加Swap空间可以作为虚拟内存使用,帮助系统处理内存压力,本文给大家介绍了CentOS7增加Swap空间的两种方法:创建新的Swa... 目录在Centos 7上增加Swap空间的方法方法一:创建新的Swap文件(推荐)方法二:调整Sww

QT6中绘制UI的两种方法详解与示例代码

《QT6中绘制UI的两种方法详解与示例代码》Qt6提供了两种主要的UI绘制技术:​​QML(QtMeta-ObjectLanguage)​​和​​C++Widgets​​,这两种技术各有优势,适用于不... 目录一、QML 技术详解1.1 QML 简介1.2 QML 的核心概念1.3 QML 示例:简单按钮

SQL 外键Foreign Key全解析

《SQL外键ForeignKey全解析》外键是数据库表中的一列(或一组列),用于​​建立两个表之间的关联关系​​,外键的值必须匹配另一个表的主键(PrimaryKey)或唯一约束(UniqueCo... 目录1. 什么是外键?​​ ​​​​2. 外键的语法​​​​3. 外键的约束行为​​​​4. 多列外键​

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代

使用Python自动化生成PPT并结合LLM生成内容的代码解析

《使用Python自动化生成PPT并结合LLM生成内容的代码解析》PowerPoint是常用的文档工具,但手动设计和排版耗时耗力,本文将展示如何通过Python自动化提取PPT样式并生成新PPT,同时... 目录核心代码解析1. 提取 PPT 样式到 jsON关键步骤:代码片段:2. 应用 JSON 样式到

Maven 插件配置分层架构深度解析

《Maven插件配置分层架构深度解析》:本文主要介绍Maven插件配置分层架构深度解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Maven 插件配置分层架构深度解析引言:当构建逻辑遇上复杂配置第一章 Maven插件配置的三重境界1.1 插件配置的拓扑

Oracle 通过 ROWID 批量更新表的方法

《Oracle通过ROWID批量更新表的方法》在Oracle数据库中,使用ROWID进行批量更新是一种高效的更新方法,因为它直接定位到物理行位置,避免了通过索引查找的开销,下面给大家介绍Orac... 目录oracle 通过 ROWID 批量更新表ROWID 基本概念性能优化建议性能UoTrFPH优化建议注

Pandas进行周期与时间戳转换的方法

《Pandas进行周期与时间戳转换的方法》本教程将深入讲解如何在pandas中使用to_period()和to_timestamp()方法,完成时间戳与周期之间的转换,并结合实际应用场景展示这些方法的... 目录to_period() 时间戳转周期基本操作应用示例to_timestamp() 周期转时间戳基

在 PyQt 加载 UI 三种常见方法

《在PyQt加载UI三种常见方法》在PyQt中,加载UI文件通常指的是使用QtDesigner设计的.ui文件,并将其转换为Python代码,以便在PyQt应用程序中使用,这篇文章给大家介绍在... 目录方法一:使用 uic 模块动态加载 (不推荐用于大型项目)方法二:将 UI 文件编译为 python 模

Python将字库文件打包成可执行文件的常见方法

《Python将字库文件打包成可执行文件的常见方法》在Python打包时,如果你想将字库文件一起打包成一个可执行文件,有几种常见的方法,具体取决于你使用的打包工具,下面就跟随小编一起了解下具体的实现方... 目录使用 PyInstaller基本方法 - 使用 --add-data 参数使用 spec 文件(