https://www.cnblogs.com/JzedyBlogs/p/10208295.html

写得非常好:

这个是Java1.8

--------------------------------

 public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
} static final int hash(Object key) {//hash函数,用于索引定位
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
} 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;//存储数据Node没有初始化,此时初始化
if ((p = tab[i = (n - 1) & hash]) == null)//(n-1)&hash用于定位,若为null,表明Node数组该位置没有Node对象,即没有碰撞
tab[i] = newNode(hash, key, value, null);//对应位置添加Node对象
else {//表明对应位置是有Node对象的,hash碰撞了
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//链表长度大于TREEIFY_THRESHOLD值,转换为红黑树结构
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))//如果找到重复的key,判断该节点和要插入的元素key是否相等,如果相等,出循环
break;
p = e;//为了遍历,和e = p.next结合来遍历
}
}
if (e != null) { // existing mapping for key//key映射的节点不为空
V oldValue = e.value;//取出节点值记录为老的节点值
if (!onlyIfAbsent || oldValue == null)//如果onlyIfAbsent为false,或者老的节点值为null,赋予新的值
e.value = value;
afterNodeAccess(e);//访问后回调
return oldValue;
}
}
++modCount;//结构性修改记录
if (++size > threshold)//判断是否需要扩容
resize();
afterNodeInsertion(evict);//插入后回调
return null;
}

put流程

1.通过hash函数计算key的hash值,调用putVal方法

2.如果hash表为空,调用resize()方法创建一个hash表

3.根据hash值索引hash表对应桶位置,判断该位置是否有hash碰撞

  3.1 没有碰撞,直接插入映射入hash表

  3.2 有碰撞,遍历桶中节点

    3.2.1 第一个节点匹配,记录该节点

    3.2.2 第一个节点没有匹配,桶中结构为红黑树结构,按照红黑树结构添加数据,记录返回值

    3.2.3 第一个节点没有匹配,桶中结构是链表结构。遍历链表,找到key映射节点,记录,退出循环。
      没有则在链表尾部添加节点。插入后判断链表长度是否大于转换为红黑树要求,符合则转为红黑树结构

    3.2.4 用于记录的值判断是否为null,不为则是需要插入的映射key在hash表中原来有,替换值,返回旧值putValue方法结束

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

static final int hash(Object key) {//hash函数,用于索引定位int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

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;//存储数据Node没有初始化,此时初始化if ((p = tab[i = (n - 1) & hash]) == null)//(n-1)&hash用于定位,若为null,表明Node数组该位置没有Node对象,即没有碰撞
tab[i] = newNode(hash, key, value, null);//对应位置添加Node对象else {//表明对应位置是有Node对象的,hash碰撞了
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))//碰撞了,且桶中第一个节点就匹配
e = p;//记录第一个节点elseif (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//链表长度大于TREEIFY_THRESHOLD值,转换为红黑树结构
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))//如果找到重复的key,判断该节点和要插入的元素key是否相等,如果相等,出循环break;
p = e;//为了遍历,和e = p.next结合来遍历
}
}
if (e != null) { // existing mapping for key//key映射的节点不为空
V oldValue = e.value;//取出节点值记录为老的节点值if (!onlyIfAbsent || oldValue == null)//如果onlyIfAbsent为false,或者老的节点值为null,赋予新的值
e.value = value;
afterNodeAccess(e);//访问后回调return oldValue;
}
}
++modCount;//结构性修改记录if (++size > threshold)//判断是否需要扩容
resize();
afterNodeInsertion(evict);//插入后回调returnnull;
}

Java HashMap的put操作(Java1.8)的更多相关文章

  1. Java HashMap的put操作(Java1.6)

    https://www.cnblogs.com/skywang12345/p/3310835.html // 存储数据的Entry数组,长度是2的幂. // HashMap是采用拉链法实现的,每一个E ...

  2. HashMap源码解析(java1.8.0)

    1.1 背景知识 1.1.1 红黑树 二叉查找树可能因为多次插入新节点导致失去平衡,使得查找效率低,查找的复杂度甚至可能会出现线性的,为了解决因为新节点的插入而导致查找树不平衡,此时就出现了红黑树. ...

  3. [翻译]Java HashMap工作原理

    大部分Java开发者都在使用Map,特别是HashMap.HashMap是一种简单但强大的方式去存储和获取数据.但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.Ha ...

  4. java对cookie的操作

    java对cookie的操作比较简单,主要介绍下建立cookie和读取cookie,以及如何设定cookie的生命周期和cookie的路径问题. 建立一个无生命周期的cookie,即随着浏览器的关闭即 ...

  5. Java学习笔记(二二)——Java HashMap

    [前面的话] 早上起来好瞌睡哈,最近要注意一样作息状态.       HashMap好好学习一下. [定义] Hashmap:是一个散列表,它存储的内容是键值对(key——value)映射.允许nul ...

  6. java集合框架之java HashMap代码解析

     java集合框架之java HashMap代码解析 文章Java集合框架综述后,具体集合类的代码,首先以既熟悉又陌生的HashMap开始. 源自http://www.codeceo.com/arti ...

  7. 【转】Java HashMap工作原理(好文章)

    大部分Java开发者都在使用Map,特别是HashMap.HashMap是一种简单但强大的方式去存储和获取数据.但有多少开发者知道HashMap内部如何工作呢?几天前,我阅读了java.util.Ha ...

  8. 【转】Java HashMap 源码解析(好文章)

    ­ .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...

  9. 转:Java HashMap实现详解

    Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1.    HashMap概述:    HashMap是基于哈希表的M ...

随机推荐

  1. go第三方日志系统-seelog-Basic sections

    https://github.com/cihub/seelog 文档学习:https://github.com/cihub/seelog/wiki 1.安装: go get github.com/ci ...

  2. javascript之Map

    javascript中的map,我用的不是特别多,倒是Java中的Map或HashMap,经常用. 顺便围绕几个方面介绍一下map? 1.Map对象 Map对象是一种有对应键值对的对象,JS的Obje ...

  3. 线程的synchronized、volatile及原子操作

    public class ThreadDemo7{ //structs2线程不安全 共享变量 //n++ 复合操作 对于volatile修饰的变量不安全 //原子操作 int value; //让方法 ...

  4. jupyter运行py文件(py文件和ipynb文件互转)

    有趣的事,Python永远不会缺席! 如需转发,请注明出处:小婷儿的python  https://i.cnblogs.com/EditPosts.aspx?postid=10750405 一.jup ...

  5. 认识与防御XSS攻击

    什么是xss攻击? XSS,即(Cross Site Scripting)中文名称为“跨站脚本攻击”.XSS的重点不在于跨站攻击而在于脚本攻击.攻击者可以利用 web应用的漏洞或缺陷之处,向页面注入恶 ...

  6. .net core实践系列之短信服务-目录

    前言 经过两周多的业余时间,终于把该系列的文章写完了.第一次写系列,可能部分关键点并没有覆盖到,如果有疑问的朋友可以随时反馈给我.另外也感谢在我发布文章时给予我方案建议与反馈源码BUG的朋友们.下面是 ...

  7. python--__init__()方法和__new__()方法

    这两个方法是python类中的基本方法,经常会在一些面试中问到.即便没有要面试之类的,学习一下其内部的原理和使用也是有必要的. 首先区分一下这两个方法: __init__:初始化方法 __new__: ...

  8. Rollup处理并打包JS文件项目实例

    关于Rollup rollup是一款用来es6模块打包代码的构建工具(支持css和js打包).当我们使用ES6模块编写应用或者库时,它可以打包成一个单独文件提供浏览器和Node.js来使用. 它的优点 ...

  9. PV、UV、IP、TPS、QPS、RPS、两天、吞吐量、 并发用户数 术语

    跟网站打交道,经常可以听到数据分析之类的专有名词,如pv多少.ip多少.tps多少之类的问题.下面就这些常见的数据给出其释义. PV   即 page view,页面浏览量         用户每一次 ...

  10. Vue(三)之前端路由

    01-前端路由 1.前端路由的实现原理 vue+vue-router 主要来做单页面应用(Single Page Application) 为什么我们要做单页面应用? (1)传统的开发方式 url改变 ...