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. 深入理解session机制

    原文链接https://blog.csdn.net/xihuangwutong/article/details/9819033 1. session概念 2. http协议与状态保持 3. 理解coo ...

  2. 【编辑器】Visual Studio Code

    1.官网:https://code.visualstudio.com/Download 2.插件:https://marketplace.visualstudio.com/VSCode https:/ ...

  3. 008_使用pyenv进行py开发环境管理

    一. 安装Python 绝大多数Python入门书籍,都会介绍如何安装Python,然而,本书要介绍一种全新的安装方式.使用pyenv来安装并管理我们的环境. pyenv简介 由于Python的依赖是 ...

  4. jenkins使用1----初始化设置

    ####一.基本设置 1.首先找到系统管理 2.再找到全局配置一把黄色的锁头 3.新增JDK.Maven等 别名随便 下面的值添加jdk在jenkins这台机器上的位置,如果没找到可以点击自动安装,并 ...

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

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

  6. Generative Adversarial Nets[Wasserstein GAN]

    本文来自<Wasserstein GAN>,时间线为2017年1月,本文可以算得上是GAN发展的一个里程碑文献了,其解决了以往GAN训练困难,结果不稳定等问题. 1 引言 本文主要思考的是 ...

  7. Python-模块导入-63

    模块导入: # 内置模块 # 扩展的 django # 自定义的 # 文件 # import demo # def read(): # print('my read func') # demo.rea ...

  8. hibernate坑边闲话

    使用hibernate各种各样的坑 Remember that ordinal parameters are 1-based node to traverse cannot be null 这两个错误 ...

  9. c++局部变量在外可用的方法

    C++的局部变量在作用域结束后,一般都会被回收.如下面这段代码 map<a*, b*> _map; void fun() { a _a; b _b; _map[&_a] = &am ...

  10. Eclipse启动错误JVM terminated. exit code 1解决方法

    现象: 前一天eclipse还用得好好的,但今天就不能用了,怎么回事? 解决方案: 请先参考其它网络资料:http://www.baidu.com/s?wd=eclipse+jvm+terminate ...