HashMap的源码,在jdk1.5中相比jdk1.4,改动不大,有几个方面
 
1 jdk1.5中引入了范型,在HashMap中也有体现
2 引入了另一个hash值的计算方式,不过默认是关闭状态,可以通过设置jvm的参数开启

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;
}
 
3 代码的小优化

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;
}
 
HashMap的源码,在jdk1.6中相比于jdk1.5也没什么改动,在这个版本开始,开始启用新的hash计算方式,把以前的废弃了

static int hash(int h) {

        h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
在jdk1.7中,相比与jdk1.6,变动也不是很大。
 
在jdk1.7中,HashMap的初始数组长度,没有设置了。可能出于内存有效使用的考虑。
   // 构造方法里并没有初始化数组
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);
}
....
}
 
这里引入了一个新方法inflateTable,初始化数组 
    // 初始化数组
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;
}
 
这里在看下hash值的生成

   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);
}
 
上面提到一个方法Integer.highestOneBit,可能看着挺困惑的,这个是Integer里的一个方法。
    // 或者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源码分析三的更多相关文章

  1. Java中HashMap源码分析

    一.HashMap概述 HashMap基于哈希表的Map接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.(除了不同步和允许使用null之外,HashMap类与Hashtab ...

  2. JDK1.8 HashMap源码分析

      一.HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时 ...

  3. Java BAT大型公司面试必考技能视频-1.HashMap源码分析与实现

    视频通过以下四个方面介绍了HASHMAP的内容 一. 什么是HashMap Hash散列将一个任意的长度通过某种算法(Hash函数算法)转换成一个固定的值. MAP:地图 x,y 存储 总结:通过HA ...

  4. Java源码解析——集合框架(五)——HashMap源码分析

    HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...

  5. HashMap源码分析(史上最详细的源码分析)

    HashMap简介 HashMap是开发中使用频率最高的用于映射(键值对 key value)处理的数据结构,我们经常把hashMap数据结构叫做散列链表: ObjectI entry<Key, ...

  6. 源码分析系列1:HashMap源码分析(基于JDK1.8)

    1.HashMap的底层实现图示 如上图所示: HashMap底层是由  数组+(链表)+(红黑树) 组成,每个存储在HashMap中的键值对都存放在一个Node节点之中,其中包含了Key-Value ...

  7. Java HashMap源码分析(含散列表、红黑树、扰动函数等重点问题分析)

    写在最前面 这个项目是从20年末就立好的 flag,经过几年的学习,回过头再去看很多知识点又有新的理解.所以趁着找实习的准备,结合以前的学习储备,创建一个主要针对应届生和初学者的 Java 开源知识项 ...

  8. tomcat源码分析(三)一次http请求的旅行-从Socket说起

    p { margin-bottom: 0.25cm; line-height: 120% } tomcat源码分析(三)一次http请求的旅行 在http请求旅行之前,我们先来准备下我们所需要的工具. ...

  9. 【JAVA集合】HashMap源码分析(转载)

    原文出处:http://www.cnblogs.com/chenpi/p/5280304.html 以下内容基于jdk1.7.0_79源码: 什么是HashMap 基于哈希表的一个Map接口实现,存储 ...

随机推荐

  1. 洛谷 题解 CF711A 【Bus to Udayland】

    先用一个字符数组存每行的座位情况(字符变量也可以) 接下来用另一个数组存最后的座位情况 好了,看代码 #include<iostream> using namespace std; boo ...

  2. chrome 监听touch类事件报错:无法被动侦听事件preventDefault

    先上错误信息: Unable to preventDefault inside passive event listener due to target being treated as passiv ...

  3. ESXi 虚拟机 提示 无法打开本地虚拟机的 xxx.vmx 的本地管道的 问题解决.

    1. 今天同事与我联系, 说一个虚拟机出现连不上, vcenter控制台关闭虚拟机之后 再次打开报错: 2. 自己最开始的解决方法 移除虚拟机, 进入服务器的datastore 重新注册, 结果发现问 ...

  4. Oracle快速运行一指禅

      对于oracle数据库下的企业级应用开发,经常会使用到新建用户,新建表空间以及数据的迁移工作.虽然目前互联网存在很多单个问题的解决方案,但是比较零散,本博文结合研发兄弟们的实际现状,提供一套完整初 ...

  5. Double write Buffer的配置

    InnoDB和XtraDB使用称为doublewrite缓冲区的特殊功能来提供数据损坏的强大保证.想法是在写入数据文件之前将数据写入主表空间中的顺序日志.如果发生部分页面写入(换句话说,写入损坏),I ...

  6. DISCO Presents Discovery Channel Code Contest 2020 Qual Task E. Majority of Balls

    Not able to solve this problem during the contest (virtual participation). The first observation is ...

  7. MCMF最大流最小割(模板)Dijkstra负权优化

    #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #include <cstdio>//sprintf islower isupp ...

  8. Web Server 分布式服务: Nginx负载均衡

    Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师Igor Sysoev所开发,供俄国大型的入口网站及搜索引擎Rambler使用.其 ...

  9. RSA加密,以及证书加密

    简单的加密:https://blog.csdn.net/qq_32523587/article/details/79092364 生成证书:https://blog.csdn.net/u0121916 ...

  10. docker 入门2 - 容器 【翻译】

    入门,第 2 部分:容器 先决条件 安装的 Docker 版本是 1.13 及以上. 读完 第一部分 用下面的命令快速测试你的环境是否完备: docker run hello-world 概述 现在开 ...