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值相等的元素较多时 ...
随机推荐
- 猜数字游戏;库的使用:turtle
myNum = print('猜字游戏\n') while True: guess = int(input('请输入一个数:')) if guess > myNum: print('不对哦猜大了 ...
- 前端ajax技术之跨域问题解决
这里我使用jquery框架的ajax技术 <script type="text/javascript" src="Assets/js/jquery.min.js&q ...
- Hibernate框架:CRM练习--保存客户
crm:customer ralation manager 客户关系管理系统 一.准备 1.创建web项目 2.导包 最终为: 3.引入静态页面 将文件复制放入项目的WebContent目录下面: 4 ...
- CentOS 7 rabbitmq 安装
OS版本:CentOS 7.2Rrlang:19.2RabbitMQ:3.6.6 1.1 erlang安装 1. http://www.erlang.org/下载erlang,解压缩,进入目录,检查环 ...
- [转]ps命令详解
原文地址:http://apps.hi.baidu.com/share/detail/32573968 转载自:http://www.cnblogs.com/wangkangluo1/archive/ ...
- 默认空间和webapps下项目部署
用eclipse默认的工作区和webapps的细节 用{WORKSPACE}表示你的eclipse的工作空间根目录,然后你打开 {WORKSPACE}\.metadata\.plugins\org.e ...
- QEMU KVM libvirt手册(4) – images
RAW raw是默认的格式,格式简单,容易转换为其他的格式.需要文件系统的支持才能支持sparse file 创建image # qemu-img create -f raw flat.img 10G ...
- 如何让 Git 使用 HTTP 代理服务器
因为我们的内部网络使用了代理,所以在 安装 OpenStack 基于 Web 的管理控制台 的时候有个小麻烦,我们的 http 代理服务器无法通过 git 协议下载 openstack-dashboa ...
- Python爬虫3-parse编码与利用parse模拟post请求
GitHub代码练习地址:①利用parse模拟post请求:https://github.com/Neo-ML/PythonPractice/blob/master/SpiderPrac04_pars ...
- 微信小程序web-view实例
微信小程序web-view实例 index.js //index.js //获取应用实例 const app = getApp() Page({ /** * 页面的初始数据 */ data: { }, ...