hashmap的put方法源码分析
put主源码如下:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
} modCount++;
addEntry(hash, key, value, i);
return null;
}
1.1、putForNullKey():当key为null的时候自动转向putForNullKey()方法,用来处理null键,将他们放到table[0]的位置,下面的是putForNullKey()方法,进来遍历entry链表,如果遍历后,发现没有key没为nulll存在,则直接添加一个entry,键为null,值为新的value;而当遍历后,发现key有null的时候,就返回就值,让新值覆盖旧值。
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}
1.2当传入的键不为null的时候,先hash一下key的hashcode值(用来避免重写hashcode方法的不完美,保证hash散布的均匀),然后使用indexFor方法来找到对应在table[]上的位置。
indexFor源码:它没有对hash表的长度取余而使用了位运算来得到索引,这是为什么呢?因为length在hashmap中默认为2的幂次方,所以length-1所得到的二进制都是1构成的,所以hash和这个length-1做与运算其实也是对hash表的长度取余。位运算快于四则运算。(这也是为什么要去size为2的幂次方的原因,因为如果取其他数值,hash碰撞几率增大,可能size的二进制某一位上是0,导致好几个table位置无法存放数据,造成空间浪费)。
static int indexFor(int h, int length) {
return h & (length-1);
}
1.3、找到新元素的table[index]后,就遍历该位置上的entry链;如果仅仅使用equals进行链上比较效率会很低,所以我们先使用hash来比较过滤。遇到相同的值就覆盖,返回旧值。如果没有相同值就直接addentry()进行头插法插入链表。
1.4、增加entry方法addentry():addentry的源码:判断当前table的size大于等于边界值并且index位置上不为空,就2倍扩容table他的大小,然后再根据传入的hash,key,value重新定向这个元素的位置。创建entry并创建。
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
} createEntry(hash, key, value, bucketIndex);
}
1.4扩容resize(扩容条件,当前容量大于边界值,并且添加的index对应的table上不为null)
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
} Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
1.5、关键是空表扩容后的拷贝到新表的方法transfer方法,下面是源码:将table上的entry进行遍历,传入的rehash用来判断是否用来重新hash,为true的话就判断key是否为null,如果为null就hash值为0,不为null就重hash,然后重定位index,然后头插法放到对应的位置上
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
1.6、最后进行createEntry(),头插法插入,最后将e传入新table[]中,表示指针指向旧值。
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
至此全部完成
hashmap的put方法源码分析的更多相关文章
- 【转】HashMap实现原理及源码分析
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景极其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...
- HashMap实现原理及源码分析之JDK8
继续上回HashMap的学习 HashMap实现原理及源码分析之JDK7 转载 Java8源码-HashMap 基于JDK8的HashMap源码解析 [jdk1.8]HashMap源码分析 一.H ...
- java-通过 HashMap、HashSet 的源码分析其 Hash 存储机制
通过 HashMap.HashSet 的源码分析其 Hash 存储机制 集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并非真正的把 Java 对象放入数组中.仅仅是把对象的 ...
- 每天学会一点点(HashMap实现原理及源码分析)
HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希 ...
- Java split方法源码分析
Java split方法源码分析 public String[] split(CharSequence input [, int limit]) { int index = 0; // 指针 bool ...
- invalidate和requestLayout方法源码分析
invalidate方法源码分析 在之前分析View的绘制流程中,最后都有调用一个叫invalidate的方法,这个方法是啥玩意?我们来看一下View类中invalidate系列方法的源码(ViewG ...
- Linq分组操作之GroupBy,GroupJoin扩展方法源码分析
Linq分组操作之GroupBy,GroupJoin扩展方法源码分析 一. GroupBy 解释: 根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值. 查询表达式: var ...
- HashMap实现原理及源码分析
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...
- HashMap实现原理及源码分析(JDK1.7)
转载:https://www.cnblogs.com/chengxiao/p/6059914.html 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技 ...
随机推荐
- Gym-101915A Printing Books 模拟
题面 题意:给你N,X, X表示这本书从X开始编号,每个X是几位数,计数器就加几, 然后问你如果从X,开始编号,计数器为N的时候,翻了几页,不能刚好为N输出-1. (例如,5 99,答案为2,因为 ...
- 集成Bmob推送
Write By lz: 转发请注明原文地址: http://www.cnblogs.com/lizhilin2016/p/6952217.html Lz 寄语: Bmob 奇葩推送, 大坑, 想要 ...
- 【Oracle】查询当前SCN
介绍两种方式: 一.sys用户下: select current_scn from v$database; select dbms_flashback.get_system_change_number ...
- Centos7 执行firewall-cmd –permanent –add-service=mysql报错“ModuleNotFoundError: No module named 'gi'”
因为目前环境Python3.x与Python2.x版本并存,所以导致以上问题. 解决方法: 第一步,vim /usr/bin/firewall-cmd, 将#!/usr/bin/python -Es ...
- spring重点一:处理对象创建时间 个数以及方式
/** * 1) 对象创建: 单例/多例(个数) * scope="singleton", 默认值, 即 默认是单例 [service/dao/工具类] * scope=&quo ...
- python数据分析------文本挖掘(jieba)
1.import jieba jieba的cut函数有三个模式:全模式.精准模式.搜索引擎模式 1 精确模式,试图将句子最精确地切开,适合文本分析: 2 全模式,把句子中所有的可以成词的词语都扫描出来 ...
- POJ 2377 Bad Cowtractors( 最小生成树转化 )
链接:传送门 题意:给 n 个点 , m 个关系,求这些关系的最大生成树,如果无法形成树,则输出 -1 思路:输入时将边权转化为负值就可以将此问题转化为最小生成树的问题了 /************* ...
- nyoj11-奇偶数分离
奇偶数分离 时间限制:3000 ms | 内存限制:65535 KB 难度:1 描述 有一个整型偶数n(2<= n <=10000),你要做的是:先把1到n中的所有奇数从小到大输出,再 ...
- BJOI2012 最多的方案
BJOI2012 最多的方案 Description 第二关和很出名的斐波那契数列有关,地球上的OIer都知道:F1=1, F2=2, Fi = Fi-1 + Fi-2,每一项都可以称为斐波那契数 ...
- 使用shell脚本定时备份web网站代码
#!/bin/bash ############### common file ################ #备份文件存放目录 WEBBACK_DIR="/data/backup/ba ...