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值相等的元素较多时 ...
随机推荐
- 异步async与await的简单探究
在学习.net core的过程中,到处见到异步的使用,Task.async.await随处可见.有点疑惑,就去了解了下这个过程是怎样的. 下面是一段代码,去看看是怎么执行的吧. 一.看看异步执行的方式 ...
- 开发HR人事考试系统介绍
确定好需要开发的模块以及功能 一套人事考试系统主要模块: 1)组织管理:公司部门成员信息 2)人事管理:人事信息,离职管理,职务管理,岗位管理: 3)考勤管理:班次设置,停工放假,假日设置,刷卡记录, ...
- centos7制作本地yum源
创建想要挂载的路径 mkdir /mnt/cdrom 挂载本地镜像到创建的目录 mount -t iso9660 /dev/cdrom /mnt/cdrom/ mount: /dev/sr0 is w ...
- SAS 函数
SAS 函数 SAS函数是编程语言的一个组件,可接受参数.执行计算或进行其他操作并返回值.返回值是字符型或数值型的结果,可用于赋值语句或 表达式中.SAS包含很多函数,也可以自定义函数.在BASE S ...
- 找出数组中最大值and索引
找出数组中的最大值和和最大值的索引位置..... 第一中方法: /** * 找出数组中最大值和最大值的索引 * @param args */ public static void main(Strin ...
- rem 原理与简介
一.rem 原理与简介 字体单位: 值根据 html 根元素大小而定,同样可以作为宽度,高度等单位 适配原理: 将 px 替换为 rem,动态修改 HTML 根元素的 font-siz ...
- 20145232韩文浩《网络对抗》PC平台逆向破解
shellcode注入 1.Linux下有两种基本构造攻击buf的方法:retaddr+nop+shellcode,nop+shellcode+retaddr.我们采用anything+retaddr ...
- js实现上传图片回显功能
用到h5技术 <img id="headimg" src="<%=path%>/resources/images/icon4.png" sty ...
- ef core 相关
1.为什么使用ef core? 市面上orm框架那么多,为何偏偏选择ef,dapper那么好用,性能碾压ef,为什么使用dapper? 对于这个问题我记得当初一个老师讲entityframework的 ...
- Git Gui for Windows的建库、克隆(clone)、上传(push)、下载(pull)、合并(转)
Git Gui for Windows的建库.克隆(clone).上传(push).下载(pull).合并(转) from:http://hi.baidu.com/mvp_xuan/blog/item ...