HashMap实现原理和源码详细分析

闲聊 闲聊 1388 人阅读 | 0 人回复

<
HashMap完成道理战源码详细阐发

ps:本专客基于Jdk1.8
  进修要面:
1、明白HashMap的数据构造
2、理解HashMap中的集列算法
3、明白HashMap中put、remove、get的代码完成
4、HashMap的哈希抵触是甚么?怎样处置的?
5、明白HashMap的扩容机造
1、甚么是HashMap?

HashMap 基于哈希表的 Map 接话柄现,是以 key-value 存储情势存正在 ,HashMap 的完成没有是同步的,那意味着它没有是线程宁静的。它的 key、value 皆能够为 null,别的,HashMap 中的映照没有是有序的。
2、HashMap的特征



  • Hash存储无序的
  • key战value皆能够存储null值,可是key只能存独一的一个null值
  • jdk8之前的数据构造是数组+链表,Jdk8以后酿成数组+链表+白乌树
  • 阀值年夜于8而且数组少度年夜于64才会转为白乌树
3、HashMap的数据构造

JDK7的状况,是数组减链接,hash抵触时分,便转换为链表:
145744dvqnn0t70vnndrp7.jpg

jdk8的状况,jdk8减上了白乌树,链表的数量年夜于8并且数组少度年夜于64以后,便转换为白乌树,白乌树节面小于6以后,便又转换为链表:
145744xop71031uu07qoi6.jpg

翻下HashMap源码,对应的节面疑息:
  1. static class Node<K,V> implements Map.Entry<K,V> {
  2.         // hashCode
  3.         final int hash;
  4.         final K key;
  5.         V value;
  6.         // 链表的next指针便没有为null
  7.         Node<K,V> next;
  8.         Node(int hash, K key, V value, Node<K,V> next) {
  9.             this.hash = hash;
  10.             this.key = key;
  11.             this.value = value;
  12.             this.next = next;
  13.         }
  14.         // ...
  15. }        
复造代码
4、HashMap初初化操作

4.1、成员变量

  1. public class HashMap<K,V> extends AbstractMap<K,V>
  2.     implements Map<K,V>, Cloneable, Serializable {
  3.         /**
  4.      * 序列号版本号
  5.      */
  6.     private static final long serialVersionUID = 362498820763181265L;
  7.    /**
  8.      * 初初化容量,为16=2的4次幂
  9.      */
  10.     static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
  11.    /**
  12.      * 最年夜容量,为2的30次幂
  13.      */
  14.     static final int MAXIMUM_CAPACITY = 1 << 30;
  15.     /**
  16.      * 默许的背载果子,默许值是0.75
  17.      */
  18.     static final float DEFAULT_LOAD_FACTOR = 0.75f;
  19.     /**
  20.      * 链表节面树超越8便转为为白乌树
  21.      */
  22.     static final int TREEIFY_THRESHOLD = 8;
  23.    
  24.     /**
  25.      * 白乌树节面少于6便再转换回链表
  26.      */
  27.     static final int UNTREEIFY_THRESHOLD = 6;
  28.    
  29.     /**
  30.      * 桶中构造转化为白乌树对应的数组少度最小的值
  31.      */
  32.     static final int MIN_TREEIFY_CAPACITY = 64;
  33.    
  34.     // ...
  35.        
  36.          /**
  37.      * HashMap存储元素的数组
  38.      */
  39.         transient Node<K,V>[] table;
  40.     /**
  41.      * 用去寄存缓存
  42.      */
  43.     transient Set<Map.Entry<K,V>> entrySet;
  44.     /**
  45.      * HashMap寄存元素的个数
  46.      */
  47.     transient int size;
  48.     /**
  49.      * 用去记载HashMap的修正次数
  50.      */
  51.     transient int modCount;
  52.     /**
  53.      * 用去调解巨细下一个容量的值(容量*背载果子)
  54.      */
  55.     int threshold;
  56.     /**
  57.      * Hash表的背载果子
  58.      */
  59.     final float loadFactor;
  60. }   
复造代码
h4a id="42__124"/a4.2、 机关办法/h4
  1. public HashMap(int initialCapacity, float loadFactor) {
  2.     // 初初容量不克不及小于0,小于0间接扔出IllegalArgumentException
  3.     if (initialCapacity < 0)
  4.         throw new IllegalArgumentException("Illegal initial capacity: " +
  5.                                            initialCapacity);
  6.      // 初初容量年夜于最年夜容量的时分,与最年夜容量做为初初容量
  7.     if (initialCapacity > MAXIMUM_CAPACITY)
  8.         initialCapacity = MAXIMUM_CAPACITY;
  9.      // 背载果子不克不及小于0,并且如果数值范例,isNan:true,暗示便长短数值范例
  10.     if (loadFactor <= 0 || Float.isNaN(loadFactor))
  11.         throw new IllegalArgumentException("Illegal load factor: " +
  12.                                            loadFactor);
  13.     // 将指定的背载果子赋值给齐局变量
  14.     this.loadFactor = loadFactor;
  15.     // threshold  = (容量) * (背载果子)
  16.     this.threshold = tableSizeFor(initialCapacity);
  17. }
  18. public HashMap(int initialCapacity) {
  19.      // 初初化容量战默许背载果子
  20.     this(initialCapacity, DEFAULT_LOAD_FACTOR);
  21. }
  22. public HashMap() {
  23.     // 默许的背载果子为0.75
  24.         this.loadFactor = DEFAULT_LOAD_FACTOR;
  25. }
复造代码
p然后,我们明白HashMap的默许容量是16,然后是正在那里赋值的?从上里那个代码就能够明白codethis.threshold = tableSizeFor(initialCapacity);/code/p
  1. static final int tableSizeFor(int cap) {
  2.     int n = cap - 1;
  3.     n |= n >>> 1;
  4.     n |= n >>> 2;
  5.     n |= n >>> 4;
  6.     n |= n >>> 8;
  7.     n |= n >>> 16;
  8.     return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
  9. }
复造代码

那里触及到计较机根本常识的,左移运算战或运算,上面给出图例:经由过程比较贫困的计较得出n为16
145745eypl3pl4762pospl.png

往代码里翻,借找到上面那个机关办法public HashMap(Map
1、本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,按照目前互联网开放的原则,我们将在不通知作者的情况下,转载文章;如果原文明确注明“禁止转载”,我们一定不会转载。如果我们转载的文章不符合作者的版权声明或者作者不想让我们转载您的文章的话,请您发送邮箱:Cdnjson@163.com提供相关证明,我们将积极配合您!
2、本网站转载文章仅为传播更多信息之目的,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证信息的正确性和完整性,且不对因信息的不正确或遗漏导致的任何损失或损害承担责任。
3、任何透过本网站网页而链接及得到的资讯、产品及服务,本网站概不负责,亦不负任何法律责任。
4、本网站所刊发、转载的文章,其版权均归原作者所有,如其他媒体、网站或个人从本网下载使用,请在转载有关文章时务必尊重该文章的著作权,保留本网注明的“稿件来源”,并自负版权等法律责任。
回复 关闭延时

使用道具 举报

 
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则