• HashMap 是一个散列桶(本质是数组+链表),散列桶就是数据结构里面的散列表,每个数组元素是一个Node节点,该节点又链接着多个节点形成一个链表,故一个数组元素 = 一个链表,利用了数组线性查找和链表修改的便利性(横向=Node数组,横向只存放每个链表第一个节点,通过数组下标维持每个Node链表第一个节点的关系;纵向=Node链表,纵向是通过链表中的next维持一个Node链表所有节点的关系)
  • HashMap 可以接受 null 键和null值,而 Hashtable 则不能
  • 每个Node节点的hash、key值都不同,故插入数据时会比对hash、key值,同则替换value,不同则插入新Node节点

  • HashMap 的put()和get()源码理解:
put()过程源码:
 1 public V put(K key, V value) {
2 return putVal(hash(key), key, value, false, true);
3 }
4 //散列算法计算key的hash值
5 static final int hash(Object key) {
6 int h;
7 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
8 }
9
10 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
11 boolean evict) {
12 Node<K,V>[] tab; Node<K,V> p; int n, i;
13 if ((tab = table) == null || (n = tab.length) == 0)
14 n = (tab = resize()).length; 【注释1】
15 if ((p = tab[i = (n - 1) & hash]) == null) 【注释2】
16 tab[i] = newNode(hash, key, value, null);
17 else {
18 Node<K,V> e; K k;
19 if (p.hash == hash &&
20 ((k = p.key) == key || (key != null && key.equals(k)))) 【注释3】
21 e = p;
22 else if (p instanceof TreeNode) 【注释4】
23 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
24 else {
25 for (int binCount = 0; ; ++binCount) {
26 if ((e = p.next) == null) {
27 p.next = newNode(hash, key, value, null); 【注释6】
28 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
29 treeifyBin(tab, hash); 【注释7】
30 break;
31 }
32 if (e.hash == hash &&
33 ((k = e.key) == key || (key != null && key.equals(k))))
34 break; 【注释5】
35 p = e;
36 }
37 }
38 if (e != null) { 【注释30】
39 V oldValue = e.value;
40 if (!onlyIfAbsent || oldValue == null)
41 e.value = value;
42 afterNodeAccess(e);
43 return oldValue;
44 }
45 }
46 ++modCount;
47 if (++size > threshold) 【注释8】
48 resize();
49 afterNodeInsertion(evict);
50 return null;
51 }
由上:hashMap插入元素时,传入hash值+key+value,先获取当前的桶=node数组,如果当前桶为null则初始化【注释1】;
然后根据key算出hash值,再根据hash值算出node数组的下标,如果对应下标位置的node节点为null则新建node节点【注释2】;
如果对应下标位置node节点不为null且该位置的hash值、key值与传入的相等,则用新节点的value覆盖该位置的value【注释3、注释30】;
如果对应下标位置node节点不为null且该位置的hash值与key值、传入的不相等:则先判断该位置是不是红黑树节点,若是则把构建并插入新的红黑树节点【注释4】;若不是红黑树节点则该位置节点是链表,则遍历该链表,遍历过程中若链表中节点得hash值、key值与传入的hash值、key值相同,则用新节点的value覆盖该位置的value【注释5、注释30】;遍历过程中若链表中节点得hash值、key值与传入的hash值、key值不相同,则在链表结尾插入新节点【注释6】,插入之后若该链表长度大于TREEIFY_THRESHOLD值=8,则把链表转为红黑树【注释7,但注释7的treeifyBin()方法并不会马上把链表转为红黑树,如果“横向=Node数组”的长度大于64时才转,小于64就扩容resize()】;
最后检查hashMap总node节点个数大于容量阀值threshold,则扩容resize()【注释8,扩容把容量和阀值都增大为2倍;疑问:在第43行的时候已经返回了value值,那么第46行以后的代码是不会执行的,那怎么扩容?】
 
 
get()过程源码:
 1 public V get(Object key) {
2 Node<K,V> e;
3 return (e = getNode(hash(key), key)) == null ? null : e.value;
4 }
5
6 final Node<K,V> getNode(int hash, Object key) {
7 Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
8 if ((tab = table) != null && (n = tab.length) > 0 &&
9 (first = tab[(n - 1) & hash]) != null) {
10 if (first.hash == hash && // always check first node
11 ((k = first.key) == key || (key != null && key.equals(k))))
12 return first; 【注释1】
13 if ((e = first.next) != null) {
14 if (first instanceof TreeNode)
15 return ((TreeNode<K,V>)first).getTreeNode(hash, key); 【注释2】
16 do { 【注释3】
17 if (e.hash == hash &&
18 ((k = e.key) == key || (key != null && key.equals(k))))
19 return e;
20 } while ((e = e.next) != null);
21 }
22 }
23 return null;
24 }
25
26 final TreeNode<K,V> getTreeNode(int h, Object k) {
27 return ((parent != null) ? root() : this).find(h, k, null);
28 }
由上:首先根据key算出hash值,再根据hash值算出node数组的下标,如果对应下标位置的链表头node节点,它的hash值、key值与传入的相等,则返回该节点value【注释1】;
如果对应下标位置的链表头node节点,它的hash值、key值与传入的不相等,则先检查该头node节点是否是红黑树节点,若是则从红黑树中查找目标节点【注释2】,即调用getTreeNode中红黑树节点的find()方法,find()源码见下图;
如果该头node不是红黑树节点而是普通的链表节点,则遍历链表查找目标节点 【注释3】;
(find方法源码在TreeNode节点=红黑树节点定义中:TreeNode继承LinkedHashMap.Entry,而LinkedHashMap.Entry继承HashMap.Node,所以TreeNode是HashMap.Node的子类,即红黑树TreeNode节点是普通链表Node节点的子类节点)

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

文章定期同步更新于公众号【小大白日志】,欢迎关注公众号:

HashMap源码理解一下?的更多相关文章

  1. HashMap源码分析

    最近一直特别忙,好不容易闲下来了.准备把HashMap的知识总结一下,很久以前看过HashMap源码.一直想把集合类的知识都总结一下,加深自己的基础.我觉的java的集合类特别重要,能够深刻理解和应用 ...

  2. Java集合---HashMap源码剖析

    一.HashMap概述二.HashMap的数据结构三.HashMap源码分析     1.关键属性     2.构造方法     3.存储数据     4.调整大小 5.数据读取           ...

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

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

  4. HashMap源码解读(转)

    http://www.360doc.com/content/10/1214/22/573136_78188909.shtml 最近朋友推荐的一个很好的工作,又是面了2轮没通过,已经是好几次朋友内推没过 ...

  5. Java中HashMap源码分析

    一.HashMap概述 HashMap基于哈希表的Map接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.(除了不同步和允许使用null之外,HashMap类与Hashtab ...

  6. 自学Java HashMap源码

    自学Java HashMap源码 参考:http://zhangshixi.iteye.com/blog/672697 HashMap概述 HashMap是基于哈希表的Map接口的非同步实现.此实现提 ...

  7. [转载] Java集合---HashMap源码剖析

    转载自http://www.cnblogs.com/ITtangtang/p/3948406.html 一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射 ...

  8. Java集合系列[3]----HashMap源码分析

    前面我们已经分析了ArrayList和LinkedList这两个集合,我们知道ArrayList是基于数组实现的,LinkedList是基于链表实现的.它们各自有自己的优劣势,例如ArrayList在 ...

  9. HashMap 源码详细分析(JDK1.8)

    一.概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值, ...

随机推荐

  1. python+pytest接口自动化(12)-自动化用例编写思路 (使用pytest编写一个测试脚本)

    经过之前的学习铺垫,我们尝试着利用pytest框架编写一条接口自动化测试用例,来厘清接口自动化用例编写的思路. 我们在百度搜索天气查询,会出现如下图所示结果: 接下来,我们以该天气查询接口为例,编写接 ...

  2. SpringBoot:自定义注解实现后台接收Json参数

    0.需求 在实际的开发过程中,服务间调用一般使用Json传参的模式,SpringBoot项目无法使用@RequestParam接收Json传参 只有@RequestBody支持Json,但是每次为了一 ...

  3. MySQL 获取每月多少日的sql写法

    # 写法1 指定 年月 的共有多少日 select DATEDIFF(DATE_ADD(CONCAT( 2020, '-', '03','-','01'),INTERVAL 1 MONTH),CONC ...

  4. Java 中怎么创建 ByteBuffer?

    byte[] bytes = new byte[10]; ByteBuffer buf = ByteBuffer.wrap(bytes);

  5. 学习Puppet(三)

    一.相关概念: 1.  puppet基于C/S架构,使用ruby编写,在类UNIX平台上集中配置管理系统,它可以管理配置文件.用户.cron任务.软件包.系统服务. 2.  puppet把系统实体称为 ...

  6. Three.js 实现3D开放世界小游戏:阿狸的多元宇宙 🦊

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 2545光年之外的开普勒1028星系,有一颗色彩斑斓的宜居星球 ,星际移民 ...

  7. IdentityServer4系列 | 混合模式

    一.前言 在上一篇关于授权码模式中, 已经介绍了关于授权码的基本内容,认识到这是一个拥有更为安全的机制,但这个仍然存在局限,虽然在文中我们说到通过后端的方式去获取token,这种由web服务器和授权服 ...

  8. 走在 SVG + Low Poly 的路上

    随着 SVG 的发展,艺术家和设计师们把越来越多传统设计行业的东西引入了前端, low poly 就是其中之一.那 low poly 强大在哪呢,大家通过下面的图来感受一下. 恰巧我们产品 Logo ...

  9. BeeFramework:以极客的方式开发你的应用

    BeeFramework 是新一代的应用开发框架,它能使应用开发变得更简单更容易,它是由 Gavin Kwoe 和 QFish 开发并维护的.使用 BeeFramework 能像 html 和 css ...

  10. Issues with position fixed & scroll(移动端 fixed 和 scroll 问题)

    转载请注明英文原文及译文出处 原文地址:Issues with position fixed & scrolling on iOS 原文作者:Remy Sharp译文地址:移动端 fixed ...