博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
源码分析(一) HashMap 源码分析|JDK8
阅读量:7170 次
发布时间:2019-06-29

本文共 3753 字,大约阅读时间需要 12 分钟。

  HashMap是一个普遍应用于各大JAVA平台的最最最常用的数据结构。<K,V>的存储形式使HashMap备受广大java程序员的喜欢。JDK8中HashMap发生了很大的变化,例如:之前在JDK7中存在的indexFor方法被移除了,哈希碰撞后不再单纯的使用链表来解决,而是使用红黑树+单向链表来解决,之前Entry<K,V>也改换为Node<K,V>。对于红黑树我觉得这个是稍微有些复杂的,包括插入和删除,红黑树的旋转和5个基本原则我觉得这个是需要花时间来慢慢整理的。对数据结构的理解一定是关键中的关键。使用红黑二叉树的主要目的就是提升了检索的效率,O(N)->O(logN)

  下面就我自己对HashMap的理解做一些总结。以下代码均来自jdk 1.8.0_73

  1. 基础部分

  (1)组成结构:通俗的说,HashMap就是结合了哈希表和链表的一种实现,在JDK8之前,之所以采用链表的目的其实是在于方便解决哈希碰撞带来的影响,提高hash值相同的插入速度。但是当一个桶转化为一个链表的时候,效率还是会有所下降。在JDK8之后采用链表+红黑树的方式来解决哈希碰撞带来的问题HashMap底层维护一个数组,数组中的每一项都是一个Node<K,V>。

1 transient Node
[] table;//哈希表 2 3 transient Set
> entrySet;//缓存

  我们向 HashMap中所存储的数据实际上是存储在该数组当中,而HashMap中的key,value则是以Node<K,V>的形式存放在数组中。而这个Node应该放在数组的哪一个位置上(这个位置通常称为位桶或者hash桶,即hash值相同的Entry会放在同一位置,用链表相连或是红黑树),是通过key的hashCode来计算的。

1 static final int hash(Object key) {2         int h;3         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);4 }

  Map的put方法:其实看起来还是有点麻烦的,源码上put方法上的注释提示了,如果key值相同则会替换。

1     /** 2      *  3      *  4      * 将给定的value映射到Map上,如果该map上存在相同的key值,则会替换为现有的值 5      * 6      * @param key key with which the specified value is to be associated 7      * @param value value to be associated with the specified key 8      * @return the previous value associated with key, or 9      *         null if there was no mapping for key.10      *         (A null return can also indicate that the map11      *         previously associated null with key.)12      */13     public V put(K key, V value) {14         return putVal(hash(key), key, value, false, true);15     }

  putVal可以划分为这样的一个流程:

    1)当前哈希表是否为空,如果为空就初始化一个

    2)然后插入这个value,要是这个数组没有就插入,有的话就替代原先的value

    3)要是hash碰撞了,看看当前位置是红黑树还是链表,然后插入。同样,要是发现key相同则进行覆盖。

    4)要是当前链表长度超过阈值了(默认是8),就转红黑树 

  这里要有个约定:

    1) 哈希表是一个大的数组,类型是Node<K,V>,规定这个是每个桶,

    2)桶里装的是bin

    3)size是node的数量,也就是你实际存放K,V的数量

    4)capacity是桶的数量,没规定初始化容量时,一般默认是16个

1  final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 2                    boolean evict) { 3         Node
[] tab; Node
p; int n, i; 4 if ((tab = table) == null || (n = tab.length) == 0) 5 n = (tab = resize()).length; 6 if ((p = tab[i = (n - 1) & hash]) == null) 7 tab[i] = newNode(hash, key, value, null); 8 else { 9 Node
e; K k;10 if (p.hash == hash &&11 ((k = p.key) == key || (key != null && key.equals(k))))12 e = p;13 else if (p instanceof TreeNode)14 e = ((TreeNode
)p).putTreeVal(this, tab, hash, key, value);15 else {16 for (int binCount = 0; ; ++binCount) {17 if ((e = p.next) == null) {18 p.next = newNode(hash, key, value, null);19 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st20 treeifyBin(tab, hash);21 break;22 }23 if (e.hash == hash &&24 ((k = e.key) == key || (key != null && key.equals(k))))25 break;26 p = e;27 }28 }29 if (e != null) { // existing mapping for key30 V oldValue = e.value;31 if (!onlyIfAbsent || oldValue == null)32 e.value = value;33 afterNodeAccess(e);34 return oldValue;35 }36 }37 ++modCount;38 if (++size > threshold)39 resize();40 afterNodeInsertion(evict);41 return null;42 }

 

转载于:https://www.cnblogs.com/showme1942/p/6479248.html

你可能感兴趣的文章
【Android SDK】在命令行管理Android SDK
查看>>
618 | “赢销备战”,全场景助力商家!
查看>>
React 基础知识总结
查看>>
ANGULAR JS常用指令NG-IF、NG-CLASS、NG-OPTION、NG-VALUE、NG-CLICK是如何使用的?
查看>>
cocos creator 视频交互游戏
查看>>
开发者日报 2019年04月09日
查看>>
React项目从Javascript到Typescript的迁移经验总结
查看>>
requirejs库的简易实现
查看>>
2017-9-16(沉浸式状态栏StatusBar)
查看>>
哈密a货翡翠,文山a货翡翠
查看>>
jQuery知识总结之事件
查看>>
假日提升计划【python篇】(回顾基础)
查看>>
Android学习笔记15-从源码分析Activity的创建过程
查看>>
SQL2005学习(一),修改登录身份和数据库默认存储路径
查看>>
命令行配置esx网络示例
查看>>
蜂窝移动网络权限关闭导致的坑
查看>>
Red Hat Enterprise Linux Systems Monitoring and Performance Turning
查看>>
CCNP路由-10 路由策略1 被动接口、控制管理距离
查看>>
SpringMVC jsonView 注解笔记
查看>>
C/S协作 以及对近期工作的一点总结
查看>>