hashMap 源码解读理解实现原理和hash冲突
hashMap 怎么说呢。 我的理解是 外表是一个set 数组,无序不重复 。 每个set元素是一个bean ,存着一对key value
看看代码吧
package test; import java.util.HashMap;
import java.util.Map.Entry; public class HashMaptest { public static void main(String[] args) { HashMap<String, String> map = new HashMap<String, String>(); String aa = "张三";
String bb = "李四";
map.put(aa, "22");
map.put(bb, "34234");
map.put("张三", "223"); System.out.println(aa.hashCode());
System.out.println(bb.hashCode()); for (Entry<String, String> entry : map.entrySet()) { System.out.println(entry.getKey()); // System.out.println(entry.getValue());
} } }
打印的结果是:
李四
张三
可以看到, 虽然张三是先插进去的, 但是确在后面打印出来,说明这个数组不是有序的, 不是list;
虽然aa 的 hashcode=774889 大于bb 的, 肯定不是根据大小插入的,应该是把 得到的hashcode 取余 , 例如 6%7 = 6 , 9%(7+1)=1 ,6>1 ,所以9 在前面,这里为什么是 第一个除以7 ,第二个进来确实% 8呢;
因为hash算法是 这样的:
int hash = key.hashCode(); // 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值
int index
= hash % Entry[].length;
Entry[index] = value;
这里看到 Entry[].length 一直在增加的;
所以就会遇到hash冲突, 总有碰到取余后一样的;
好了,举个例子:
比如 key="张三", hashcode=666 ,entry的size是 100 666%100=66 ;存在 66 位置上。 这个时候 key="李四" 要插入了, hashcode =6666 entry的size是 6600 6666%6600=66 , 这样 66 位置就hash冲突了;
这里和我代码写的覆盖不是一回事 。 代码的 key 相同,这里在特别说明下:可能有人说, 两个张三的hashcode 一样, 不同时候插入,entry 的 size不是不一样吗, 那就不会覆盖了? 这么想是错误的, 其实 map 插入的时候是先比较equals 的, 发现,咦 ,相同, 直接覆盖原值
:附上 hashMap的Put 方法源码:
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);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
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) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
可能比较难懂, 主要在这句:
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
已存在的key ,之而立是直接覆盖的。
hashMap 源码解读理解实现原理和hash冲突的更多相关文章
- HashMap源码解读(转)
http://www.360doc.com/content/10/1214/22/573136_78188909.shtml 最近朋友推荐的一个很好的工作,又是面了2轮没通过,已经是好几次朋友内推没过 ...
- HashMap源码解读(JDK1.7)
哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表,而HashMap的实现原理也常常出 ...
- 深入理解JAVA集合系列一:HashMap源码解读
初认HashMap 基于哈希表(即散列表)的Map接口的实现,此实现提供所有可选的映射操作,并允许使用null值和null键. HashMap继承于AbstractMap,实现了Map.Cloneab ...
- jdk 8 HashMap源码解读
转自:https://www.cnblogs.com/little-fly/p/7344285.html 在原来的作者的基础上,增加了本人对源代码的一些解读. 如有侵权,请联系本人 这几天学习了Has ...
- HashMap源码解读
1.HashMap 1.6解读 a).put,get,遍历方式参看 http://www.cnblogs.com/skywang12345/p/3310835.html#a23 需要注意的是,1.7 ...
- HashMap源码解读(jdk1.8)
1.相关常量 默认初始化容量(大小) static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 最大容量 static final int M ...
- HashMap 源码解读
HashMap在JDK1.7和1.8中有了很大的改变,空闲时间对HashMap做了一点点的研究. HashMap是一种数组和链表结合的数据结构,我们每次new一个HashMap时,都会构造出一个长度为 ...
- java集合之HashMap源码解读
源自:jdk1.8.0_121 HashMap继承自AbstractMap,实现了Map.Cloneable.Serializable. HashMap内部是由数组.链表.红黑树实现的 变量 // 默 ...
- 探索HashMap源码 一行一行解析 jdk1.7版本
今天我们来说一说,HashMap的源码到底是个什么? 面试大厂这方面一定会经常问到,很重要的.以jdk1.7 为标准 先带着大家过一遍 是由数组.链表组成 , 数组的优点是:每个元素有对应下标, ...
随机推荐
- 命令学习_IPCONFIG: DNS cache操作
IPCONFIG: DNS cache操作 Windows会将解析到的DNS信息缓存,这个机制可以加速重复的域名访问.从DNS Server返回的DNS Response消息中带有"Time ...
- springboot整合mybatis进行跨库查询
业务场景: 当一个公司大了之后就会将各种业务进行分开,最简单的就是例如:公司的机构表,那么就会将他们分成开来,那么就会在一个实例中, 如果要获取相关信息就会去关联这张表进行关联查询 从而导致了跨库关联 ...
- python基础语法(运算符及优先级)
python基础语法(运算符及优先级) python语言支持的运算符类型 算数运算符 假设变量a为10,变量b为21 算数符 描述 实例 + 加-两个对象相加 a+b结果31 - 减-得到一个负数或者 ...
- 17-7-es6作用域
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- cv2 & PIL(pillow)显示图像
= OpenCV和PIL中显示图像方式不一样,且支持的格式也不同 = cv在显示图像时是自定义的显示窗口,而PIL中显示是调用操作系统中的默认打开程序 如: import cv2 im = cv2.i ...
- logger----->模块级别的函数
#_author:star#date:2019/11/6#logger----->模块级别的函数#文件与屏幕同时显示日志信息import logginglogger=logging.getLog ...
- LUOGU P1313 计算系数 (组合数学)
解题思路 比较简单的题,用二项式定理即可. #include<iostream> #include<cstdio> #include<cstring> #inclu ...
- Jenkins 简单安装使用
一.介绍 Jenkins 是一款业界流行的开源持续集成工具,广泛用于项目开发,具有自动化构建.测试和部署等功能.由于 jenkins是基于java环境运行的,所以首先需要安装java环境 二.安装 1 ...
- 基于MFC的实时可视化项目中视图刷新消息的严谨使用
在实时可视项目中,视图的实时刷新显示对软件的体验感来说非常重要,当算法的效率达到实时,比如一秒40帧,如果实时显示帧率更不上,则体验感将大大折扣,让用户感觉你的算法并没有40帧,当然最关键的是解决显示 ...
- linux ssh密钥认证, 免密码登陆
1. 客户端生成密钥 # mkdir ~/.ssh # chmod ~/.ssh # cd ~/.ssh 生成RSA密钥 # ssh-keygen -t rsa (然后连续三次回车) 2. 把公钥传到 ...