前置位运算知识

我们平时在写代码过程中用的位运算操作比较少,因为我们更关注于可读性而不是性能,如果为了性能而使用较多的位运算,我想我们的同事会疯掉。但在框架里位运算却非常常见,因为框架的性能是我们关注的点。下面就来一起回顾一下常见的位运算操作:

<< : 左移运算符,num << 1,相当于num乘以2  低位补0
>> : 表示右移,如果该数为正,则高位补 0,若为负数,则高位补 1。
>>> : 表示无符号右移,也叫逻辑右移,即若该数为正,则高位补 0,而若该数为负数,则右移后高位同样补 0。
% : 模运算 取余
^ : 位异或 第一个操作数的的第n位于第二个操作数的第n位相反,那么结果的第n为也为1,否则为0
& : 与运算 第一个操作数的的第n位于第二个操作数的第n位如果都是1,那么结果的第n为也为1,否则为0
| : 或运算 第一个操作数的的第n位于第二个操作数的第n位 只要有一个是1,那么结果的第n为也为1,否则为0
~ : 非运算 操作数的第n位为1,那么结果的第n位为0,反之,也就是取反运算(一元操作符:只操作一个数)

HashMap的hash函数算法

 static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

此时我们心中会有两个疑惑:

  • 为什么要无符号右移 16 位后做异或运算
  • key 本身的 hashCode 直接拿来用不行吗

来看这样一个例子:

将 h 无符号右移 16 为相当于将高区 16 位移动到了低区的 16 位,再与原 hashcode 做异或运算,可以看作是将高低位二进制特征混合起来

从上图中可以看出,高位的 16 位与原 hashcode 相比没有发生变化,低位的 16 位发生了变化。

上面的 (h = key.hashCode ()) ^ (h >>> 16) 进行运算后,可以把高区与低区的二进制特征混合到低区,那么为什么要这么做呢?

我们要知道,上面计算出来的hashcode值接下来要参与到hashmap中数组槽位的计算,其计算公式是:(n - 1) & hash,现在假设数组槽位大小是16,那么槽位计算过程如下:

观察可以看出,如果我们不做刚才移位异或运算,那么在计算槽位时将丢失高区特征。也许你可能会说,即使丢失了高区特征,不同 hashcode 也可以计算出不同的槽位来,但是细想当两个哈希码很接近时,那么这高区的一点点差异就可能导致一次哈希碰撞,所以这也是将性能做到极致的一种体现。

为什么要采用异或运算

异或运算能更好的保留各部分的特征,如果采用 & 运算计算出来的值会向 1 靠拢,采用 | 运算计算出来的值会向 0 靠拢。

为什么槽位数必须使用 2^n

这里假设槽位数不是 16,而是 17,那么槽位计算公式就变成:(17 - 1) & hash。

可以看出计算结果将会大大趋同,hashcode 参加 & 运算后被更多位的 0 屏蔽,计算结果只剩下两种,分别是0 和 16,这对于 hashmap 来说是一种灾难。

总结

HashMap当中运用了很多精巧的位运算操作,这对于提高性能有很大帮助,更多的,很多的优化点,最终目的还是为了让哈希后的结果更均匀的分部,减少哈希碰撞,提升 hashmap 的运行效率。

参考文章

[1] https://zhuanlan.zhihu.com/p/149583558
[2] https://juejin.im/entry/5e1a960d5188254c257c38e5
[3] https://www.jianshu.com/p/eb9ab4211163

HashMap位运算你可知一二的更多相关文章

  1. 我们必须要了解的Java位运算(不仅限于Java)

    本文原创地址为 https://www.cnblogs.com/zh94/p/16195373.html 原创声明:作者:陈咬金. 博客地址:https://www.cnblogs.com/zh94/ ...

  2. HDU 4949 Light(插头dp、位运算)

    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...

  3. Java位运算总结:位运算用途广泛《转》

    前天几天研究了下JDK的Collection接口,本来准备接着研究Map接口,可是一查看HashMap类源码傻眼咯,到处是位运算实现,所以我觉得还是有必要先补补位运算知识,不然代码看起来有点费力.今天 ...

  4. Java学习之位运算和逻辑运算符

    今天看了一下HashMap类的源码,在HashMap的源码中定义了初始空间的大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 当 ...

  5. C语言学习笔记之位运算求余

    我们都知道,求一个数被另一个数整除的余数,可以用求余运算符”%“,但是,如果不允许使用求余运算符,又该怎么办呢?下面介绍一种方法,是通过位运算来求余,但是注意:该方法只对除数是2的N次方幂时才有效. ...

  6. Python语言中的按位运算

    (转)位操作是程序设计中对位模式或二进制数的一元和二元操作. 在许多古老的微处理器上, 位运算比加减运算略快, 通常位运算比乘除法运算要快很多. 在现代架构中, 情况并非如此:位运算的运算速度通常与加 ...

  7. java位运算(操作)的使用

    位操作是程序设计中对位模式按位或二进制数的一元和二元操作. 在许多古老的微处理器上, 位运算比加减运算略快, 通常位运算比乘除法运算要快很多. 在现代架构中, 情况并非如此:位运算的运算速度通常与加法 ...

  8. 136.Single Number---异或、位运算

    题目链接 题目大意:给出一串数组,里面的数都是两个,只有一个数是一个,把这个只有一个的数找出来.时间复杂度最好是线性的,空间复杂度最好为O(1). 法一:利用map,空间换时间,代码如下(耗时26ms ...

  9. string与位运算

    1.String String  a="abc";  会在常量池中开辟一个空间,保存"abc" String  b=new String("abc&q ...

随机推荐

  1. rabbitMQ结合spring-boot使用(1)

    从这一节开始我们进入rabbitMQ的实战环节,项目环境是spring-boot 加maven.首先让我们创建一个spring-boot项目,然后引入web依赖和 rabbitMQ的依赖 <de ...

  2. C++虚函数相关内容

    样例代码 class Base{public: Base(){}; virtual ~Base(){    //若没有设置为虚函数:如果有这样的指针Base *p=new Derived();声明,则 ...

  3. subprocess.CalledProcessError: Command '['ninja', '-v']' returned non-zero exit status 1.

    将anaconda环境下的  lib/python3.5/dist-packages/torch/utils/cpp_extension.py文件 将['ninja','-v']改成['ninja', ...

  4. 【模式识别与机器学习】——PCA与Kernel PCA介绍与对比

    PCA与Kernel PCA介绍与对比 1. 理论介绍 PCA:是常用的提取数据的手段,其功能为提取主成分(主要信息),摒弃冗余信息(次要信息),从而得到压缩后的数据,实现维度的下降.其设想通过投影矩 ...

  5. Java Redis系列3(Jedis的使用+jedis连接池技术)

    Jedis的使用 什么是Jedis? 一款Java操作redis数据库的工具 使用步骤 1.下载redis所需的java包 2.使用步骤 import org.junit.Test; public c ...

  6. JAVA—继承及抽象类

    继承的概念 在Java中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法. 与css中继承父元素属性类似 继承的 ...

  7. JavaScript Object的defineProperty / getOwnPropertyDescriptor

    getOwnPropertyDescriptor and defineProperty function def (obj, key, val, enumerable) { Object.define ...

  8. Memcached高可用组件之repcached

    在前边的tomcat session server msm的那篇博客我们用memcached做tomcat session服务器,默认官方memcached是不支持主从同步的,为了解决memcache ...

  9. Windows下,配置VS Code的Java开发环境

    Windows下,配置VS Code的Java开发环境 前言 最近痴迷于VS Code的开发环境配置,原因就在于它的轻巧和免费,还能当一个非常棒的文本编辑器.如果之前你配置过VS Code并且失败了, ...

  10. 触发链模式之使用jdk的Observable和Observerver实现触发链模式(附JDK源码)

    首先看看JDK的Observer接口 public interface Observer { void update(Observable o, Object arg); } 也就一个更新的方法,这里 ...