基于jdk1.8

hashMap实现,要求容量大小是2的整次方,例如:2/4/8/16/32/64/128...,而不能是中间的某个值。这是为什么呢?

map是数组+链表的数据结构,读写数据都需要首先获取数组中的下标值,获取的方式是通过hashcode取余。取余so easy,我们都会,假定运算后的hashcode=17,容量大小capacity=16,17%16=1,很容易得出元素落在数组的下标[1]内。

但是还有一种方式可以获取到正确的下标值,17 &(16-1)=1。

17二进制: 10001

15二进制: 01111

17&15:     00001 = 1

计算机的物理特性,决定位运算才是取余的正确打开方式。但是却有一个限制,被位与的数值有效位必须全部都是1,如15:1111可以,13:1101则不行。

这里位与运算得到的是下标位置,数组容量要在最大下标值的基础上加1,等价于二进制中被位与的数值进位,如15进1位=16:10000,2的4次方。

如果我们new HashMap<>(13),输入一个非整次方的数值,hashmap会自动调整成最近的整次方,例如这里的13最终会转换成16,实现方法为:java.util.HashMap#tableSizeFor

怎么实现呢?

2的整次方的特性是二进制有效位只有一个1,退位后当前1消失,后面bit位全补1,例如16:10000,退位后01111。13的二进制:1101,结构上看只要第二个bit补1(1101->1111),再进位(1111->10000)就可以了。1101->1111->

我们来分析实现

首先把方法复制出来,加上一些日志方便分析:

static final int MAXIMUM_CAPACITY = 1 << 30;

static final int tableSizeFor(int cap) {
System.out.println(Integer.toBinaryString(cap));
int n = cap - 1;
System.out.println(Integer.toBinaryString(n));
n |= n >>> 1;
System.out.println(Integer.toBinaryString(n));
n |= n >>> 2;
System.out.println(Integer.toBinaryString(n));
n |= n >>> 4;
System.out.println(Integer.toBinaryString(n));
n |= n >>> 8;
System.out.println(Integer.toBinaryString(n));
n |= n >>> 16;
System.out.println(Integer.toBinaryString(n));
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
} public static void main(String[] args) {
tableSizeFor(MAXIMUM_CAPACITY);
}
int n = cap - 1先退位,所以最终实现的结果是n的bit位全补1。

使用的最大容量+1,这样看日志比较清晰。

1000000000000000000000000000001
1000000000000000000000000000000
1100000000000000000000000000000
1111000000000000000000000000000
1111111100000000000000000000000
1111111111111111000000000000000
1111111111111111111111111111111

看到规律了吗?tableSizeFor首先获取最高位的1,二进制退位规则决定一定能够获取到最高位的1,然后进行不停的bit复制,1生2,2生4等等。int类型只有32位,所以复制到16位终止。

最后将n进位,即得到2的整次方,不过限定不能大于1>>30;

hashMap tableSizeFor 实现原理的更多相关文章

  1. Java中HashMap底层实现原理(JDK1.8)源码分析

    这几天学习了HashMap的底层实现,但是发现好几个版本的,代码不一,而且看了Android包的HashMap和JDK中的HashMap的也不是一样,原来他们没有指定JDK版本,很多文章都是旧版本JD ...

  2. HashMap底层实现原理(JDK1.8)源码分析

    ref:https://blog.csdn.net/tuke_tuke/article/details/51588156 http://www.cnblogs.com/xiaolovewei/p/79 ...

  3. 一文搞定HashMap的实现原理和面试

    原文  https://juejin.im/post/5d09f2d56fb9a07ec7551fb0 HashMap在日常开发中基本是天天见的,而且都知道什么时候需要用HashMap,根据Key存取 ...

  4. HashMap的工作原理

    HashMap的工作原理   HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...

  5. HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别

    ①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...

  6. HashMap的工作原理深入再深入

    前言 首先再次强调hashcode (==)和equals的真正含义(我记得以前有人会说,equals是判断对象内容,hashcode是判断是否相等之类): equals:是否同一个对象实例.注意,是 ...

  7. [转] HashMap的工作原理

    HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此 ...

  8. 【转】HashMap的工作原理

    很好的文章,推荐Java的一个好网站:ImportNew HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hasht ...

  9. 转:HashMap的工作原理,及笔记

    HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道Hashtable和HashMap之间的区别,那么为何这道面试题如此 ...

随机推荐

  1. hashCode() 和equals() 区别和作用(转)

    出处:https://www.jianshu.com/p/5a7f5f786b75 本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么 ...

  2. pytorch总结

    PyTorch 深度学习:60分钟快速入门 用例子学习 PyTorch 手把手教你用PyTorch从零搭建图像分类模型

  3. IntelliJ IDEA 2017版 编译器使用学习笔记(六) (图文详尽版);IDE快捷键使用

    一.alter + enter使用 应用于很对场景不知道如何操作代码时使用          1.场景一:自动创建函数         调用一个没有的函数的时候,alter+enter,弹出自动创建函 ...

  4. IntelliJ IDEA 2017版 spring-boot2.0.2 搭建 JPA springboot DataSource JPA环境搭建,JPA注解@ManyToOne使用详情;JPA外键设置

    一.数据库原型 数据库模型如图所示,而现在需要根据数据库模型,建立对应的实体类,这在项目重构老数据库,采用新的框架重构上应该是比较常见的. 数据库脚本如下: CREATE TABLE `bomsub` ...

  5. VS2008卡死无反映解决

    终于解决了我的vs卡死的问题.最初只发现打开aspx页面会卡死,打开cs文件不会.并且每次卡死都会发现进程中有启动“setup.exe”,这是office的修复程序.这样就很好理解了,vs中的设计视图 ...

  6. Hibernate关联关系配置(一对多,一对一,多对多)

    一对多 创建两个类  Manager(一这一端) Worker(多这一端)  即一个经理下有多个员工 package com.hibernate.n21; import java.util.HashS ...

  7. Warning the user/local/mysql/data directory is not owned by the mysql user

    sudo chown -RL root:mysql /usr/local/mysql sudo chown -RL mysql:mysql /usr/local/mysql/data sudo /us ...

  8. 基于MATLAB的腐蚀膨胀算法实现

    本篇文章要分享的是基于MATLAB的腐蚀膨胀算法实现,腐蚀膨胀是形态学图像处理的基础,腐蚀在二值图像的基础上做“收缩”或“细化”操作,膨胀在二值图像的基础上做“加长”或“变粗”的操作. 什么是二值图像 ...

  9. The writing on the wall

              题意:一个n*m的方格矩阵,有的格子被涂成了黑色,问该矩阵中有多少个子矩阵,子矩阵不包含黑色格子; 思路:对于一个长为L, 高为H的无黑点矩阵中包含的高为H的子矩阵个数为L+(L- ...

  10. Android中去掉标题栏

    在Android中去掉标题栏有三种方法,它们也有各自的特点. 1.在代码里实现 this.requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏 记 ...