HashMap源码中的位运算符&详解

引言

最近在读HashMap源码的时候,发现在很多运算符替代常规运算符的现象。比如说用hash & (table.length-1) 来替代取模运算hash&(table.length);用if((e.hash & oldCap) == 0)判断扩容后元素的位置等等。

1.取模运算符%底层原理

​总所周知,位运算&直接对二进制进行运算;而对于取模运算符%:a % b 相当于 a - a / b * b,底层实际上是除法器,究其根源也是由底层的减法和加法共同完成。所以其运行效率要远远小于位运算符&。

2.位运算符&如何实现取模功能

​我们先来看两个例子

5 & 7                9 & 7
0101----5            1001----9
&                         &
0111----7             0111----7
=                          =
0101----5             0001----1

​确实,hash & (table.length-1) 来实现了运算hash&(table.length)从二进制的角度来说,5%8实际上是将二进制5(0101)向右移动3位,而与7(0111)进行与运算实际上就是将位数向右移动三位。不过要注意的是,只有当length的长度为2^n时,结论才成立。

3.位运算符&在if((e.hash & oldCap) == 0)判断扩容后元素的位置

​这是出自于JDK1.8中扩容函数resize()的一行代码,用于判断在扩容后原数组中的元素是否需要移动。举个例子:

0001 1010----26                0000 1010----10                
&                              &
0001 0000----16                0001 0000----16
=                              =
0001 0000----非0               0000 0000-----0

利用hash值和oldCap进行与运算,很明显当结果大于0代表hash值大于oldCap时,下标位置变为旧数组的下标j + oldCap;若结果等于0代表小于oldCap,则下标位置不变。相比于JDK1.7重新计算每个元素的哈希值,通过高位运算(e.hash & oldCap)无疑效率更高。

到此这篇关于HashMap源码中的位运算符&详解的文章就介绍到这了,更多相关HashMap源码中的位运算符&内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JAVA中哈希表HashMap的深入学习

    深入浅出学Java--HashMap 哈希表(hash table) 也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,本文会对java集合框架中HashMap的实现原理进行讲解,并对JDK7的HashMap源码进行分析. 一.什么是哈希表 在讨论哈希表之前,我们先大概了解下其他数据结构在新增,查找等基础操作执行性能 数组:采用一段连续的存储单元来存储数据.对于指定下标的查找,时间复杂度为O(1):通过给定值进

  • Java实现简易HashMap功能详解

    本文实例讲述了Java实现简易HashMap功能.分享给大家供大家参考,具体如下: 创建节点类 节点类含有的属性:键值对(value,key)以及指向下一节点的next: 这些属性的get以及set方法 代码如下: /** * 节点类 * @author HP * */ public class Node { private Object value; private Object key; private Node next; /** * 空节点 */ public Node() { } /*

  • 学习Java HashMap,看这篇就够了

    HashMap 是一个散列表,它存储的内容是键值对(key-value)映射. HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步. HashMap 是无序的,即不会记录插入的顺序. HashMap 继承于AbstractMap,实现了 Map.Cloneable.java.io.Serializable 接口. HashMap 的 key 与 value 类型可以相同也可以不同,可以是字符串(Str

  • JAVA--HashMap热门面试题

    1. 为什么我们建议在定义HashMap的时候,就指定它的初始化大小呢? 答:在当我们对HashMap初始化时,如果没有为其设置初始化容量,那么系统会默认创建一个容量为16的大小的集合.当我们向HashMap中添加元素时,如果HashMap的容量值超过了它的临界值(默认16*0.75=12)时,(0.75是HashMap的加载因子)HashMap将会重新扩容到下一个2的指数次幂(2^4=16 下一个2的指数次幂是2^5=32).由于HashMap扩容要进行resize的操作,频繁的resize,

  • Java5种遍历HashMap数据的写法

    本文介绍了最好的Java5种遍历HashMap数据的写法,分享给大家,也给自己留一个笔记,具体如下: 通过EntrySet的迭代器遍历 Iterator < Entry < Integer, String >> iterator = coursesMap.entrySet().iterator(); while (iterator.hasNext()) { Entry < Integer, String > entry = iterator.next(); System

  • Java HashMap原理及实例解析

    这篇文章主要介绍了Java HashMap原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 示例 1 : HashMap的键值对 HashMap储存数据的方式是-- 键值对 package collection; import java.util.HashMap; public class TestCollection { public static void main(String[] args) { HashMap<String

  • Java手写简易版HashMap的使用(存储+查找)

    HashMap的基本结构 package com.liuyuhe; public class Node { int hash; Object key; Object value; Node next; } package com.liuyuhe; public class MyHashMap { Node[] table; //位桶数组 int size; //存放键值对的个数 public MyHashMap() { table=new Node[16]; } } put()方法存储键值对 p

  • Java使用HashMap实现并查集

    并查集的定义: 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中.这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述. 并查集是一种树型的数

  • java中hashmap容量的初始化实现

    HashMap使用HashMap(int initialCapacity)对集合进行初始化. 在默认的情况下,HashMap的容量是16.但是如果用户通过构造函数指定了一个数字作为容量,那么Hash会选择大于该数字的第一个2的幂作为容量.比如如果指定了3,则容量是4:如果指定了7,则容量是8:如果指定了9,则容量是16. 为什么要设置HashMap的初始化容量 在<阿里巴巴Java开发手册>中,有一条开发建议是建议我们设置HashMap的初始化容量. 下面我们通过具体的代码来了解下为什么会这么

  • HashMap源码中的位运算符&详解

    引言 最近在读HashMap源码的时候,发现在很多运算符替代常规运算符的现象.比如说用hash & (table.length-1) 来替代取模运算hash&(table.length):用if((e.hash & oldCap) == 0)判断扩容后元素的位置等等. 1.取模运算符%底层原理 ​总所周知,位运算&直接对二进制进行运算:而对于取模运算符%:a % b 相当于 a - a / b * b,底层实际上是除法器,究其根源也是由底层的减法和加法共同完成.所以其运行效

  • Android源码中的目录结构详解

    Android 2.1 |-- Makefile |-- bionic                        (bionic C库) |-- bootable                (启动引导相关代码) |-- build                        (存放系统编译规则及generic等基础开发包配置) |-- cts                        (Android兼容性测试套件标准) |-- dalvik                    

  • C++位运算符详解(异或运算符和移位运算符)

    什么是位运算 位运算符按二进制进行运算,这些运算符只能用于整数类型的操作.如:char,short,int,long 通过位运算符来获取高位值和低位值 int a=0x1234; int high,low; high = (a>>8) &0x00ff; low = a & 0x00ff; 左移运算符和右移运算符(<<和>>) 左移是将一个二进制数,移动若干位,右边空出的位置用0来填补,高位左移溢出应该舍弃该高位. 如:inta = 8, a = 0000

  • php源码 fsockopen获取网页内容实例详解

    PHP fsockopen函数说明: Open Internet or Unix domain socket connection(打开套接字链接) Initiates a socket connection to the resource specified by target . fsockopen() returns a file pointer which may be used together with the other file functions (such as fgets(

  • Spring-boot 2.3.x源码基于Gradle编译过程详解

    spring Boot源码编译 1. git上下拉最新版的spring Boot 下载:git clone git@github.com:spring-projects/spring-boot.git,建议下载release版本,不会出现奇奇怪怪的错误 2.修改下载源, gradle\wrapper中的配置文件 gradle-wrapper.properties distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists #d

  • RocketMQ源码解析topic创建机制详解

    目录 1. RocketMQ Topic创建机制 2. 自动Topic 3. 手动创建--预先创建 通过界面控制台创建 1. RocketMQ Topic创建机制 以下源码基于Rocket MQ 4.7.0 RocketMQ Topic创建机制分为两种:一种自动创建,一种手动创建.可以通过设置broker的配置文件来禁用或者允许自动创建.默认是开启的允许自动创建 autoCreateTopicEnable=true/false 下面会结合源码来深度分析一下自动创建和手动创建的过程. 2. 自动T

  • Python3中的算术运算符详解

    目录 一·算术运算符 二·代码演示 1·求和 + 2·取差 - 3·相乘 * 4·相除 / 5·取余 % 6·幂运算 ** 7·整除 // 8·优先级混合运算 三·'+'与'*'在序列中的使用 1·拼接合并 + 2·复制 * 一·算术运算符 在python中,算术运算符与数学中的算术运算极为类似,只是有些运算符号有所差别.算术运算符的算术计算一般是运用于int类型与floa类型,同时+与*还可以运用到各种序列的拼接合并与复制中. 优先级:有括号先算括号内的,再乘方>乘除>整除>取余>

  • 详细聊聊React源码中的位运算技巧

    目录 前言 几个常用位运算 按位与(&) 按位或(|) 按位非(-) 标记状态 优先级计算 总结 前言 这两年有不少朋友和我吐槽React源码,比如: 调度器为什么用小顶堆这种数据结构,直接用数组不行? 源码里各种单向链表.环状链表,直接用数组不行? 源码里各种位运算,有必要么? 作为业务依赖的框架,为了提升一点点运行时性能,React从不吝惜将源码写的很复杂. 在涉及状态.标记位.优先级操作的地方大量使用了位运算. 本文会讲解其中比较有代表性的部分.学到之后,当遇到类似场景时露一手,你就是业务

  • Vue源码分析之虚拟DOM详解

    为什么需要虚拟dom? 虚拟DOM就是为了解决浏览器性能问题而被设计出来的.例如,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内容保存到本地一个JS对象中,最终将这个JS对象一次性attch到DOM树上,再进行后续操作,避免大量无谓的计算量.简单来说,可以把Virtual DOM 理解为一个简单的JS对象,并且最少包含标签名( tag).属性(attrs)和子元素对象( children)三个属性. ----- 元素节点: 元素节点更贴近于我们

  • 手写Vue源码之数据劫持示例详解

    源代码: 传送门 Vue会对我们在data中传入的数据进行拦截: 对象:递归的为对象的每个属性都设置get/set方法 数组:修改数组的原型方法,对于会修改原数组的方法进行了重写 在用户为data中的对象设置值.修改值以及调用修改原数组的方法时,都可以添加一些逻辑来进行处理,实现数据更新页面也同时更新. Vue中的响应式(reactive): 对对象属性或数组方法进行了拦截,在属性或数组更新时可以同时自动地更新视图.在代码中被观测过的数据具有响应性 创建Vue实例 我们先让代码实现下面的功能:

随机推荐