java HashMap
HashMap 的性能因子
1. 容量:表示桶位的数量。
2. 初始容量: 表在创建是所拥有的桶位数。
- 如果你知道将要在HashMap存储多少项,创建一个初始容量合适的HashMap将可以避免自动再散列的开销
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
HashMap构造器
HashMap(int initialCapacity, float loadFactor);
initialCapacity为初始容量, loadFactor为负载因子
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY) // 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); // tableSizeFor(initialCapacity) 会返回x(x表示2的整数次幂)
//threshold是一个阙值,它等于 负载因子*尺寸, 当然这里暂时等于容量
//当调用resize函数后才开始真正分配空间(槽位),这时才赋给threshold真正意义上的值
}
来看看tableSizeFor的实现(个人绝对想不到这么高大上的方法)
/**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1; //这里是因为考虑到cap为2的整数次幂的情况 //1. 假设此时n的二进制最高位1在第i位(最低位为第0位) n |= n >>> 1; //2. 此时n的二进制第i, i-1位都为1 n |= n >>> 2; //3. 此时n的二进制第i, i-1, i-2, i-3位都为1 n |= n >>> 4; //4. 此时n的二进制第i, i-1, i-2, i-3, i-4, i-5, i-6, i-7位都为1(当然,严谨点应该再假设i>7) n |= n >>> 8;
//5.---------
n |= n >>> 16;
//6.---------
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
添加元素
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
/**
* Implements Map.put and related methods
*
* @param hash hash for key
* @param key the key
* @param value the value to put
* @param onlyIfAbsent if true, don't change existing value
* @param evict if false, the table is in creation mode.
* @return previous value, or null if none
*/
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null) // 判断是否发生冲突
tab[i] = newNode(hash, key, value, null); // 没反生冲突,直接放入第i个槽位
else {
//执行到这里,表示发生冲突了
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p; //如果key相等,直接把新value覆盖原value
else if (p instanceof TreeNode) //判断当前解决冲突所用的数据结构是不是TreeNode(红黑树)
//这是当冲突过多(某个槽位冲突数超过TREEIFY_THRESHOLD=8)时,
//HashMap的优化方式
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
// 执行到这里说明当前解决冲突所用结构是链表
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // 冲突数超过TREEIFY_THRESHOLD
// 用红黑树代替链表
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { //如果map存在与新key相等的key,直接把新value覆盖原value
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold) //判断当前尺寸是否大于阙值(即负载是否大于负载因子)
resize();
afterNodeInsertion(evict);
return null;
}
博客园(FOREVER_ENJOY):http://www.cnblogs.com/zyx1314/p/5359434.html
本文版权归作者所有;欢迎转载!请注明文章作者和原文连接
java HashMap的更多相关文章
- [翻译]Java HashMap工作原理
大部分Java开发者都在使用Map,特别是HashMap.HashMap是一种简单但强大的方式去存储和获取数据.但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.Ha ...
- Java学习笔记(二二)——Java HashMap
[前面的话] 早上起来好瞌睡哈,最近要注意一样作息状态. HashMap好好学习一下. [定义] Hashmap:是一个散列表,它存储的内容是键值对(key——value)映射.允许nul ...
- java集合框架之java HashMap代码解析
java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...
- HashMap的原理与实 无锁队列的实现Java HashMap的死循环 red black tree
http://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html https://zh.wikipedia.org/wiki/%E7%BA ...
- 【转】Java HashMap工作原理(好文章)
大部分Java开发者都在使用Map,特别是HashMap.HashMap是一种简单但强大的方式去存储和获取数据.但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.Ha ...
- 【转】Java HashMap 源码解析(好文章)
.fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...
- 转:Java HashMap实现详解
Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1. HashMap概述: HashMap是基于哈希表的M ...
- 自学Java HashMap源码
自学Java HashMap源码 参考:http://zhangshixi.iteye.com/blog/672697 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提 ...
- Java HashMap工作原理及实现
Java HashMap工作原理及实现 2016/03/20 | 分类: 基础技术 | 0 条评论 | 标签: HASHMAP 分享到:3 原文出处: Yikun 1. 概述 从本文你可以学习到: 什 ...
- 【转】Java HashMap的死循环
问题的症状 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题.后来,我们的程序性能有问题,所以需要变成多线程的,于是,变成多线程后到了线上,发现 ...
随机推荐
- globalization与全球化
本配置节是关于配置应用程序的全球化设置. <globalization <!--以下两个特性默认编码为 UTF-8,该编码在 Machine.config 文件(在安装 .NET Fram ...
- Visual Studio 2013 Unit Test Project App.config文件设置方法
开放中经常会要做单元测试,新的项目又没有单元测试项目,怎么才能搭建一个单元测试项目呢? 下面跟我四步走,如有错误之处,还请指正! 1.添加项目 2.添加配置文件 新建app.config文件,注意不是 ...
- autocad2008+C#2008开发中设置自动加载dll
一.复制编译后的dlll路径,比如我的是D:\zjy\cad开发\学习\宗地图\bin\Debug\zd.dll 二.随便找个地方新建一个记事本,在记事本中写入以下内容: (command " ...
- 简单工厂模式和策略模式结合使用php
策略模式是有客户端自行实例化算法类的,而简单工厂模客户端只传参数,不关心对象的生成. 结合两种模式,可以在使用策略模式的时候客户端不再生成算法的对象.修改策略模式的配置类即可. 在之前策略模式基础上, ...
- 【工业串口和网络软件通讯平台(SuperIO)教程】五.二次开发图形显示界面
SuperIO相关资料下载:http://pan.baidu.com/s/1pJ7lZWf 1.1 图形显示接口的作用 用于显示采集终端设备的数据,可以把不同类型设备的数据以多种形式集成显示在不 ...
- 十一个行为模式之备忘录模式(Memento Pattern)
定义: 在不破坏原有封装的情况下,捕获一个对象的内部状态,并在对象之外保存.当对象出错或者无效是,可以根据该备忘录进行恢复. 结构图: Originator:原发类,被记录的对象,包含若干内部状态.一 ...
- python字符串连接的N种方式
python中有很多字符串连接方式,今天在写代码,顺便总结一下: 最原始的字符串连接方式:str1 + str2 python 新字符串连接语法:str1, str2 奇怪的字符串方式:str1 st ...
- 聊聊JVM的年轻代
1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的 唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候 ...
- Thinkcmf:页面常用函数
Thinkcmf:页面常用函数 全站seo: 文章列表: {$site_seo_title} <!--SEO标题--> {$site_seo_keywords} < ...
- js for循环中i++ 和 ++i有什么区别?
平时都是这样写的for循环, for(var i = 0; i < 20 ; i++){ .... } 但我看有的人这样写 for (var i = 0; i < 20 ; ++i) { ...