HashMap源码之构造函数--JDK1.8
构造函数
变量解释
- capacity,表示的是hashmap中桶的数量,初始化容量initCapacity为16,第一次扩容会扩到64,之后每次扩容都是之前容量的2倍,所以容量每次都是2的次幂
- loadFactor,负载因子,衡量hashmap一个满的程度,初始默认为0.75
- threshold,hashmap扩容的一个标准,每当size大于这个标准时就会进行扩容操作,threeshold等于capacity*loadfacfactor
HashMap(int initialCapacity, float loadFactor)
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegalinitial 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;
this.threshold = tableSizeFor(initialCapacity);
}
//构造函数前面都很容易理解,无非是设置正确的initialCapacity和loadFactor
//最后一行调用的tableSizeFor(initialCapacity);如下
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
tableSizeFor(...)方法的作用在于找到大于等于initialCapacity的最小的2的幂。n右移一位再同自身进行或操作使得n的最高位和最高位的下一位都为1.
n |= n >>> 1;
比如n=9,则n=1001(2),n-1=100
1001
0100
-----
1100
这是因为或操作的要求为相同位上只要存在1则结果为1,全为0结果才为0.一个数最高位为1,右移一位后的数最高位也为1,不论相对应的位上另一个数是多少结果依旧为1.
而对于n |= n >>> 2n的最高位及其下一位都为1,右移两位后再进行或操作将使得得到的n的前4位都为1,类似的n |= n >>> 4使得前8位为1,n |= n >>> 8使得前16位为1。当然并不是说该方法调用下来就会使得返回的值是一个32位都为1的数字,这是因为当右移的位数操作实际的有效位数后是不会对数字产生任何变化的。
以n=9为例,在进过两次右移后n=1111(2)
00000000000000000000000000001111 n (int 32位)
00000000000000000000000000000000 n>>>4
--------------------------------
00000000000000000000000000001111
当n右移4位后全部变成了0,使得结果不会发生任何变化,后面的n |= n >>> 8等等也一样
在最后返回的时候做了一个判断(n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1,正常来说返回的是一个n+1,在前面的操作中已经将前几位有效的数字变成了1(n=1111),这里加1使得n=10000(2),即变为大于等于initialCapacity的最小的2的幂,到这里貌似就差不多了,但是在tableSizeFor(...)方法的第一句有一个减法操作int n = cap - 1;这是为什么呢?这里减1实际上是为处理传入的数本身就是2的幂的情况。比如我传入的是n=8=1000(2),如果不进行减1操作,得到的则是n=10000(2)=16,实际上我需要的就是8.
HashMap(Map<? extends K, ? extends V> m)
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
}
这个构造函数主要是用一个已有的map来构造一个新的HashMap,这里主要在于putMapEntries(m, false);中。
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}
前面几行是做容错判断,当table没有初始化或者传入的map容量大于当前map的阈值(threshold),都需要重新进行设置。从for循环开始则是将传入的map的值插入到当前map中。
HashMap源码之构造函数--JDK1.8的更多相关文章
- HashMap 源码分析 基于jdk1.8分析
HashMap 源码分析 基于jdk1.8分析 1:数据结构: transient Node<K,V>[] table; //这里维护了一个 Node的数组结构: 下面看看Node的数 ...
- HashMap 源码详细分析(JDK1.8)
一.概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值, ...
- hashmap源码解析,JDK1.8和1.7的区别
背景:hashmap面试基础必考内容,需要深入了解,并学习其中的相关原理.此处还要明白1.7和1.8不通版本的优化点. Java 8系列之重新认识HashMap Java 8系列之重新认识HashMa ...
- HashMap源码分析-基于JDK1.8
hashMap数据结构 类注释 HashMap的几个重要的字段 hash和tableSizeFor方法 HashMap的数据结构 由上图可知,HashMap的基本数据结构是数组和单向链表或红黑树. 以 ...
- HashMap源码解读(jdk1.8)
1.相关常量 默认初始化容量(大小) static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 最大容量 static final int M ...
- HashMap源码解析(JDK1.8)
package java.util; import sun.misc.SharedSecrets; import java.io.IOException; import java.io.Invalid ...
- HashMap源码之常用方法--JDK1.8
常用方法 hash(key) static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCo ...
- JDK1.8 HashMap源码
序言 触摸本质才能永垂不朽 HashMap底层是基于散列算法实现,散列算法分为散列再探测和拉链式.HashMap 则使用了拉链式的散列算法,并在JDK 1.8中引入了红黑树优化过长的链表.数据结构示意 ...
- JDK1.8 HashMap源码分析
一.HashMap概述 在JDK1.8之前,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时 ...
随机推荐
- String Match
Finding length of longest common substring /*Finding length of longest common substring using DP * * ...
- python第三天基础之字符编码
一 了解字符编码的知识储备 1. 文本编辑器存取文件的原理(nodepad++,pycharm,word) 打开编辑器就打开了启动了一个进程,是在内存中的,所以在编辑器编写的内容也都是存放与内存中的, ...
- 关于Eclipse导入项目jsp出现红色叉的解决办法
简单图解概括 右击项目 到这里就ok 如果没解决就检查下以下三个地方的版本是否一致 如果还不行,有什么疑问可以留言,我会及时帮助解决的
- Unicode vs. UTF-8 etc.
目测是个老问题了.随便一搜,网上各种总结过.这里不辞啰嗦,尽量简洁的备忘一下. 几个链接,有道云笔记链接,都是知乎上几个问题的摘录:阮一峰的日志,1-5 还是值得参考,但是之后的部分则混淆了 Wind ...
- Jquery 在子页面上设置父页面元素的值
使用情景:因为我父页面上有用art.dialog,而子页面上有项目中的框架弹出方法跟art.dialog冲突,不能使用art.dialog自带的方法传值, 所以只好用一种简单粗暴的方法来设置. var ...
- php中测试运行的时间,从而选择得出优化程序
对于新手来说,优化代码的习惯十分重要, 测试运行的时间,从而得出最好的一个 <?php $t1=microtime(true); //获取程序1,开始的时间 程序1(代码...) $t2=m ...
- Base64格式上传文件至阿里云(java)
Controller @PostMapping("/save") public R save(@RequestBody ShareEntity share){ OSSClient ...
- all about
1.三次握手和四次挥手?2.什么是OSI七层结构?3.http vs https?4.what is Ping?基于什么协议?使用方法?5.DNS?6.cookie vs session?7.LDAP ...
- SQL Server AlwaysOn搭建
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/高性能解决方案 概述 环境: 域服务器:windows server 2008 R2 SP1,192.168.2.10 DNS:1 ...
- Senparc.Weixin SDK v5.0 升级公告
经过五年半的持续维护,Senparc.Weixin SDK 逐步丰满和完善,在升级的过程中,我们为基础库(Senparc.Weixin.dll)加入了许多通用的功能,例如加密/解密算法.通用缓存方法等 ...