Java源码之HashMap的hash篇
提到哈希,我们脑袋中立马就会闪过一个方法,就是hashCode(),没错。就是这个!
我们知道HashMap是通过 数组+链表 的结构进行数据存储的,有数组就会有索引,而HashMap内的数据要存储在哪块索引上,则是基于HashMap内部的hash方法计算出来的。
我们常用的 get put 也离不开这个 hash 方法。
我们先从hash方法入手!
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
首先通过 hashCode() 方法得到 h ,然后在把 h 无符号右移16位,最后通过异或算法得到hash值,我们找个key展开运算一下
假设有一个key
String key = "hello world";
那么这个key的hashCode的二进制为
0110 1010 1110 1111 1110 0010 1100 0100
然后把这个二进制数据向右无符号移动16位,得到如下
0000 0000 0000 0000 0110 1010 1110 1111
最后通过把高16位和低16位做异或运算均匀分布
0110 1010 1110 1111 1000 1000 0010 1011
给hash做异或运算主要还是为了降低hash冲突的概率(这个是查阅资料得知的)
我们说完hash的运算过程后,看一下HashMap里边都是哪里有用到吧
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
这三个方法,算是HashMap内最常用的三个方法了,可以看到从应用层传递进来的key全部都经过了hash(key)而比较细心的朋友们还会发现HashMap内数组的索引,是通过 i = (n - 1) & hash 计算得出的
我们接下来在展开一下索引计算公式
n是HashMap内的哈希表的长度,默认是16,每次扩容都是一倍一倍的扩容,就是 16 << 1 ,我们拿16来展开运算,而hash用上面的key来继续运算
i = (16 - 1) & hash
15的二进制结果是
0000 0000 0000 0000 0000 0000 0000 1111
hash的再拿过来用吧~(十进制:1794082859)
0110 1010 1110 1111 1000 1000 0010 1011
在通过&运算,可以得到(十进制:11)
0000 0000 0000 0000 0000 0000 0000 1011
十进制计算:
1794082859 & 15 = 11
1794082859 % 16 = 11
首先n在HashMap里的设定是永远都是2次幂,因为 2次幂 & hash(key) 等价于 hash(key) % n
而众所周知,& 比 % 效率要高10倍的。
但这个公式只有 n 是2次幂的时候才成立,所以才有了2次幂的设定。
HashMap的索引都是通过这个算法得出来的,所以HashMap查找起来特别快~
好了,通过这篇文章,大家应该也对HashMap的hash有点概念了。
Java源码之HashMap的hash篇的更多相关文章
- 浅析Java源码之HashMap
写这篇文章还是下了一定决心的,因为这个源码看的头疼得很. 老规矩,源码来源于JRE1.8,java.util.HashMap,不讨论I/O及序列化相关内容. 该数据结构简介:使用了散列码来进行快速搜索 ...
- JAVA源码分析-HashMap源码分析(一)
一直以来,HashMap就是Java面试过程中的常客,不管是刚毕业的,还是工作了好多年的同学,在Java面试过程中,经常会被问到HashMap相关的一些问题,而且每次面试都被问到一些自己平时没有注意的 ...
- Java源码学习:HashMap实现原理
AbstractMap HashMap继承制AbstractMap,很多通用的方法,比如size().isEmpty(),都已经在这里实现了.来看一个比较简单的方法,get方法: public V g ...
- Java源码之HashMap
一.HashMap和Hashtable的区别 (1)HashMapl的键值(key)和值(value)可以为null,而Hashtable不可以 (2)Hashtable是线程安全类,而HashMap ...
- 浅析Java源码之HashMap外传-红黑树Treenode(已鸽)
(这篇文章暂时鸽了,有点理解不能,点进来的小伙伴可以撤了) 刚开始准备在HashMap中直接把红黑树也过了的,结果发现这个类不是一般的麻烦,所以单独开一篇. 由于红黑树之前完全没接触过,所以这篇博客相 ...
- Java源码阅读HashMap
1类签名与注释 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cl ...
- Java源码解析|HashMap的前世今生
HashMap的前世今生 Java8在Java7的基础上,做了一些改进和优化. 底层数据结构和实现方法上,HashMap几乎重写了一套 所有的集合都新增了函数式的方法,比如说forEach,也新增了很 ...
- JAVA源码分析-HashMap源码分析(二)
本文继续分析HashMap的源码.本文的重点是resize()方法和HashMap中其他的一些方法,希望各位提出宝贵的意见. 话不多说,咱们上源码. final Node<K,V>[] r ...
- java源码之HashMap和HashTable的异同
代码版本 JDK每一版本都在改进.本文讨论的HashMap和HashTable基于JDK 1.7.0_67 1. 时间 HashTable产生于JDK 1.1,而HashMap产生于JDK 1.2.从 ...
随机推荐
- Mybatis-09-缓存
缓存 什么是缓存[Cache]? 存在内存中的临时数据 提高查询效率,解决高并发的性能问题 为什么使用缓存? 减少和数据库的交互次数,减少系统开销,提高系统效率 什么样的数据能使用缓存? 经常查询且不 ...
- idea的热加载与热部署
一:热加载与热部署 热部署的意思就是不用手动重启环境,修改类后,项目会自动重启.但是如果项目比较大,重启也需要耗时十几秒左右. 热加载意为不需要重新启动,修改了什么文件就重新加载什么文 ...
- 【算法•日更•第二十三期】数据结构:two-pointer(尺取法)&莫队
▎引入 ☞『例题』 一道十分easy的题: 洛谷P1638 长度为n的序列,m种数 找一个最短区间,使得所有数出现一遍 n≤1e6 ,m≤2e3. ☞『分析』 这道题非常的简单,但是如果不会two-p ...
- python3中文输出乱码的问题
最近使用you-get这个工具下载视频,发现命令行窗口里显示的媒体标题是乱码(但文件管理器里显示正常).我的命令行窗口的code page是936,sys.stdout.encoding是utf-8, ...
- Android 在代码中修改TextView的DrawableRight等方向上的图片
在XML文件中可以对TextView进行设置: android:drawableTop="@drawable/XXX" android:drawableBottom="@ ...
- gpio模拟i2c驱动
前段时间做项目,需要gpio模拟i2c通信,最后参考了一些资料,然后编写了一个程序.现在发出来,以免以后忘记,也为一些需要的朋友提供参考.不喜勿喷哈. /* 说明:该程序是基于atmel公司的sama ...
- Intelligence Beyond the Edge: Inference on Intermittent Embedded Systems
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! 以下是对本文关键部分的摘抄翻译,详情请参见原文. Abstract 能量收集技术为未来的物联网应用提供了一个很有前景的平台.然而,由于这些 ...
- Shell编程—创建函数
1基本的脚本函数 函数是一个脚本代码块,你可以为其命名并在代码中任何位置重用.要在脚本中使用该代码块时,只要使用所起的函数名就行了. 1.1创建函数 有两种格式可以用来在bash shell脚本中创建 ...
- 服务器里Centos 7安装KVM,并通过KVM安装Centos 7
一.安装KVM 1.进入系统后,检查cpu参数是否支持虚拟化: [root@localhost ~]# grep -Ei 'vmx|svm' /proc/cpuinfo 如果有出现vmx或者svm关键 ...
- Linux操作命令和工具使用
lrzsz是一个unix通信套件提供的X,Y,和ZModem文件传输协议. windows 需要向centos服务器上传文件,可直接在centos上执行命令yum -y install lrzsz 程 ...