HashMap源码分析三
private static int oldHash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
} private static int newHash(int h) { h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
} static int hash(int h) {
return useNewHash ? newHash(h) : oldHash(h);
}
// -XX:+UseNewHashFunction or -XX:+AggressiveOpts 启动新的hash计算
private static final boolean useNewHash;
static {
useNewHash = false;
}
public V get(Object key) {
// key为null时,取value的过程抽离到一个方法里
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
// 构造方法里并没有初始化数组
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor); this.loadFactor = loadFactor;
// 数组增长阀值,先设置成数组的初始长度
threshold = initialCapacity;
init();
} public V put(K key, V value) {
// 如果数组没有初始化,开始初始化
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
....
}
// 初始化数组
private void inflateTable(int toSize) {
// 计算确认初始化数组的长度
int capacity = roundUpToPowerOf2(toSize);
// 重新给数组长度的阀值赋值
threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
table = new Entry[capacity];
// 这里是判断是否需要给hash值生成添加生成因子,减少hash碰撞的概率
initHashSeedAsNeeded(capacity);
} // 获得初始化数组的长度
private static int roundUpToPowerOf2(int number) {
// 分几种情况
// 1 number超过数组长度限制最大值,则返回数组长度的最大值
// 2 number小于或者等于1, 则返回1
// 3 否则返回Integer.highestOneBit((number - 1) << 1),这个表示number二进制表示时,最左边位数的值为1,其他位为0时的值
// 比如 0000 0000 0000 0000 1011 0011 0000 0000 计算后值为 0000 0000 0000 0000 1000 0000 0000 0000
return number >= MAXIMUM_CAPACITY
? MAXIMUM_CAPACITY
: (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
} // 初始化是否使用hash值生成的生成因子
final boolean initHashSeedAsNeeded(int capacity) {
// 判断是否已经使用了生成因子,hashSeed=0表示未使用
boolean currentAltHashing = hashSeed != 0;
// 判断是否使用生成因子
boolean useAltHashing = sun.misc.VM.isBooted() &&
(capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
boolean switching = currentAltHashing ^ useAltHashing;
if (switching) {
hashSeed = useAltHashing
? sun.misc.Hashing.randomHashSeed(this)
: 0;
}
return switching;
}
final int hash(Object k) {
int h = hashSeed;
// 如果key对象是字符串,则换个方式生成hash值
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
// 添加生成因子
h ^= k.hashCode(); // This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
// 或者i最高位为1,其他位为0时的值
// 如:0000 0000 0000 0000 1011 0011 0000 0000 计算后值为 0000 0000 0000 0000 1000 0000 0000 0000
public static int highestOneBit(int i) {
// 开始位运算
i |= (i >> 1);// i左移1位,在和i值或运算,得到值的最高位和第2位都为1 (如果最高为到最右端不到2位,则最高位到最右端都为1)
i |= (i >> 2);// 新的i左移2位,在和i值或运算,得到值的最高位到第4位都为1 (如果最高为到最右端不到4位,则最高位到最右端都为1)
i |= (i >> 4);// 新的i左移4位,在和i值或运算,得到值的最高位到第8位都为1 ( 如果最高为到最右端不到8位,则最高位到最右端都为1)
i |= (i >> 8);// 新的i左移8位,在和i值或运算,得到值的最高位到第16位都为1 (如果最高为到最右端不到16位,则最高位到最右端都为1)
i |= (i >> 16);// 新的i左移16位,在和i值或运算,得到值的最高位到第32位都为1 (如果最高为到最右端不到32位,则最高位到最右端都为1)
// 非最高位设置为0
return i - (i >>> 1);
}
HashMap源码分析三的更多相关文章
- Java中HashMap源码分析
一.HashMap概述 HashMap基于哈希表的Map接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.(除了不同步和允许使用null之外,HashMap类与Hashtab ...
- JDK1.8 HashMap源码分析
一.HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时 ...
- Java BAT大型公司面试必考技能视频-1.HashMap源码分析与实现
视频通过以下四个方面介绍了HASHMAP的内容 一. 什么是HashMap Hash散列将一个任意的长度通过某种算法(Hash函数算法)转换成一个固定的值. MAP:地图 x,y 存储 总结:通过HA ...
- Java源码解析——集合框架(五)——HashMap源码分析
HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...
- HashMap源码分析(史上最详细的源码分析)
HashMap简介 HashMap是开发中使用频率最高的用于映射(键值对 key value)处理的数据结构,我们经常把hashMap数据结构叫做散列链表: ObjectI entry<Key, ...
- 源码分析系列1:HashMap源码分析(基于JDK1.8)
1.HashMap的底层实现图示 如上图所示: HashMap底层是由 数组+(链表)+(红黑树) 组成,每个存储在HashMap中的键值对都存放在一个Node节点之中,其中包含了Key-Value ...
- Java HashMap源码分析(含散列表、红黑树、扰动函数等重点问题分析)
写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...
- tomcat源码分析(三)一次http请求的旅行-从Socket说起
p { margin-bottom: 0.25cm; line-height: 120% } tomcat源码分析(三)一次http请求的旅行 在http请求旅行之前,我们先来准备下我们所需要的工具. ...
- 【JAVA集合】HashMap源码分析(转载)
原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储 ...
随机推荐
- Java基础语法知识你真的都会吗?
第一阶段 JAVA基础知识 第二章 Java基础语法知识 在我们开始讲解程序之前,命名规范是我们不得不提的一个话题,虽说命名本应该是自由的,但是仍然有一定的"潜规则",通过你对命名 ...
- vscode 安装一些快捷配置
Visual Studio Code 最好的功能.插件和设置 小编推荐:掘金是一个高质量的技术社区,从 ECMAScript 6 到 Vue.js,性能优化到开源类库,让你不错过前端开发的每一个技 ...
- [转帖].NET导出Excel的四种方法及评测
.NET导出Excel的四种方法及评测 https://www.cnblogs.com/sdflysha/p/20190824-dotnet-excel-compare.html 导出Excel是.N ...
- HanLP-地名识别调试方法
HanLP收词特别是实体比较多,因此特别容易造成误识别.下边举几个地名误识别的例子,需要指出的是,后边的机构名识别也以地名识别为基础,因此,如果地名识别不准确,也会导致机构名识别不准确. 类型1 数字 ...
- Oracle 10g 归档日志满了的解决办法
如果Oracle的归档日志满了,应用连接数据库就会出错,这时需要手工删除过期的归档日志,方法如下: 1.指定数据库实例 $ export ORACLE_SID=db1 2.进入rman $ rman ...
- sql server中实现mysql的find_in_set函数
charindex(','+'test'+',',','+Picture+',')>0
- python学习-3 python基础-1基础知识和解释器
1.基础知识 ~后缀名是可以是任意的 ~导入模块时,如果不是.py就会报错 =>>所以尽量后缀名携程.py 2.执行方式 -python解释器 3. #!/usr/bin/env py ...
- 二、python数据类型、字符编码、文件处理
一. 前言 1. 什么是数据: x = 10,10就是我们要存储的数据 2. 为何数据要分不同的类型 数据是用来表示状态的, 不同的状态就应该用不同类型的数据去表示 3. 数据类型 数字(整型.长整型 ...
- Linux:删除一个目录下的所有文件,但保留一个指定文件
面试题:删除一个目录下的所有文件,但保留一个指定文件 解答: 假设这个目录是/xx/,里面有file1,file2,file3..file10 十个文件 [root@oldboy xx]# touc ...
- IntelliJ IDEA 统一设置编码为utf-8编码
问题一: File->Settings->Editor->File Encodings 问题二: File->Other Settings->Default Settin ...