一、HashMap (JDK8)put(K key, V value)底层实现

1. 首先判断这个hashmap是否为空,为空就初始化一个hashmap

2. 根据key 计算hashcode()值,和数组长度-1 进行&(等价于求余), 得到bucket的位置

3. 得到位置后 判断该处的值是否为空 如果为空 直接插入

4. 如果不为空,判断数组后面链接的是否是一棵树,是树就将其put到这颗树中。

5. 不是树,先挂在链表后面,然后判断链表大小是否大于8,大于8就要把链表转换成树

源码:

  1. public V put(K key, V value) {
  2. return putVal(hash(key), key, value, false, true);
  3. }
  4. /**
  5. * Implements Map.put and related methods
  6. *
  7. * @param hash hash for key
  8. * @param key the key
  9. * @param value the value to put
  10. * @param onlyIfAbsent if true, don't change existing value
  11. * @param evict if false, the table is in creation mode.
  12. * @return previous value, or null if none
  13. */
  14. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  15. boolean evict) {
  16. Node<K,V>[] tab;
  17. Node<K,V> p;
  18. int n, i;
  19. if ((tab = table) == null || (n = tab.length) == 0)
  20. n = (tab = resize()).length;
  21. /*如果table的在(n-1)&hash的值是空,就新建一个节点插入在该位置*/
  22. if ((p = tab[i = (n - 1) & hash]) == null)//&相当于取余
  23. tab[i] = newNode(hash, key, value, null);
  24. /*表示有冲突,开始处理冲突*/
  25. else {
  26. Node<K,V> e;
  27. K k;
  28. /*检查第一个Node,p是不是要找的值*/
  29. if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))
  30. e = p;
  31. else if (p instanceof TreeNode)//数组后面是否为树,如果是树则将其put到树中
  32. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value)
  33. else {//否则挂在链表后面
  34. for (int binCount = 0; ; ++binCount) {
  35. /*指针为空就挂在后面*/
  36. if ((e = p.next) == null) {
  37. p.next = newNode(hash, key, value, null);
  38. //如果冲突的节点数已经达到8个,看是否需要改变冲突节点的存储结构,             
  39.             //treeifyBin首先判断当前hashMap的长度,如果不足64,只进行
  40. //resize,扩容table,如果达到64,那么将冲突的存储结构为红黑树
  41. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  42. treeifyBin(tab, hash);
  43. break;
  44. }
  45. /*如果有相同的key值就结束遍历*/
  46. if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))
  47. break;
  48. p = e;
  49. }
  50. }
  51. /*就是链表上有相同的key值*/
  52. if (e != null) { // existing mapping for key,就是key的Value存在
  53. V oldValue = e.value;
  54. if (!onlyIfAbsent || oldValue == null)
  55. e.value = value;
  56. afterNodeAccess(e);
  57. return oldValue;//返回存在的Value值
  58. }
  59. }
  60. ++modCount;
  61. /*如果当前大小大于门限,门限原本是初始容量*0.75*/
  62. if (++size > threshold)
  63. resize();//扩容两倍
  64. afterNodeInsertion(evict);
  65. return null;
  66. }

二、扩容

hashmap 默认大小16,每次扩大两倍(增加一倍),加载因子默认是0.75,当 hashmap容量大于 数组长度 * 加载因子的时候就会扩容,也就是初始达到12 的时候就会扩容

扩容时先重建一个2倍长度的数组,然后重新 hash

加载因子表示数组填充的程度,加载因子越大填充的越满,空间利用率越高,但冲突越大,加载因子越小,空间利用率越低,但冲突小,一般平衡在0.75

为什么每次数组的大小都是2的次幂?

1.在计算哈希桶下标的时候hash值和 数组长度减一按位与,数组长度是2的倍数减一二进制表示都是1,速度快;

2. hash & (array.length-1)相当于对array.length-1 取模运算,也就是 % 运算,&效率比%高;

3.数组长度是2的次幂,不同key求的hash值相同几率很小,冲突小,查询快

 三、HashMap和HashTable的区别

1. hashmap 的 key  可以为 null,hashtable不行,为空时,hashcode默认为0。

2. hashtable是线程安全的,方法前面都有 synchronized 关键字。

3. hashtable继承Dictionary 类,hashmap继承 AbstractMap类,但都实现了 Map、Cloneable、Serializable接口

四、如何保证HashMap线程安全

1. 使用ConcurrentHashMap

2. Collections.synchronizedMap(new HashMap<String, Integer>());

深入理解HashMap底层实现原理的更多相关文章

  1. HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别(转)

    HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别 文章来源:http://www.cnblogs.com/beatIteWeNerverGiveU ...

  2. Java面试必问之Hashmap底层实现原理(JDK1.7)

    1. 前言 Hashmap可以说是Java面试必问的,一般的面试题会问: Hashmap有哪些特性? Hashmap底层实现原理(get\put\resize) Hashmap怎么解决hash冲突? ...

  3. HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别

    ①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...

  4. Java中HashMap底层实现原理(JDK1.8)源码分析

    这几天学习了HashMap的底层实现,但是发现好几个版本的,代码不一,而且看了Android包的HashMap和JDK中的HashMap的也不是一样,原来他们没有指定JDK版本,很多文章都是旧版本JD ...

  5. HashMap底层实现原理

    HashMap底层实现 HashMap底层数据结构如下图,HashMap由“hash函数+数组+单链表”3个要素构成 通过写一个迷你版的HashMap来深刻理解 MyMap接口,定义一个接口,对外暴露 ...

  6. (转)HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别

    ①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...

  7. HashMap底层实现原理(JDK1.8)源码分析

    ref:https://blog.csdn.net/tuke_tuke/article/details/51588156 http://www.cnblogs.com/xiaolovewei/p/79 ...

  8. HashMap底层实现原理以及HashMap与HashTable区别以及HashMap与HashSet区别

    ①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...

  9. 【转载】HashMap底层实现原理及面试问题

    ①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...

随机推荐

  1. Mysql 游标的定义与使用方式

    创建游标: 首先在MySql中创建一张数据表: CREATE TABLE IF NOT EXISTS `store` (   `id` int(11) NOT NULL AUTO_INCREMENT, ...

  2. Android Studio CMake依赖第三方库

    这里实现一个简单的功能在APP里调用libnative-lib.so里的add.libnative-lib.so去调用libthird.so里的third_add来实现 JniUtil public ...

  3. override javascript escape funcation

    var oldescape = window.escape; escape = function (sStr) { return oldescape(sStr).replace(/\+/g, '%2B ...

  4. nodejs卸载安装

    作为新手nodejs卸载后安装就总出错,今天记录了详细的步骤: 参考一下网址:写的很详细https://jingyan.baidu.com/article/48b37f8dd141b41a646488 ...

  5. spring整合web的ssh(springMVC、hibernate)

    1. tomcat启动时,加载配置文件,将bean装在 导入jar包spring-web..jar 2.确定配置文件位置 3.spring整合hibernate <!-- 加载hibernate ...

  6. Sharepoint2010新建一个用户的方法

    最近在做关于SharePoint的相关开发,在开发中需要用到测试用户进行相关权限的测试,所以就需要创建一个新的用户进行,但是在网上找了很久都没有找到关于创建一个新用户的资料,最后终于在http://w ...

  7. pm2的的常用命令及用法

    使用pm2启动静态文件服务器的方法如下: pm2 serve path port pm2 serve . 9001 这样就可以把当前文件夹下的静态文件跑起来了,而且端口号是9001, 同样也支持进阶的 ...

  8. AndroidStudio多AppId多渠道快速打包

    一直感觉AndroidStudio没有eclipse快,但是最近由于遇到一个问题不得不将工程迁移到AndroidStudio上,迁移后之前在eclipse上所做的所有批量打包又得重新在AndroidS ...

  9. 《ArcGIS Runtime SDK for Android开发笔记》——(1)、Android Studio下载与安装

    1.前言 Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工 ...

  10. 创建Podspec 并且发布到github spec

    昨天,花了点时间,把自己的代码做成framework,但是发现,每次迁移项目或者更新项目都是一件很头疼的事情,索性,也跟着时尚了一回,把所有代码都扔到git里面进行管理,通过cococapods直接安 ...