一、概念

允许key为null,value为null;线程不安全;不保证映射的顺序;迭代 collection 视图所需的时间与 HashMap 实例的“容量”(桶的数量)及其大小(键-值映射关系数)成比例;HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数;加载因子默认是0.75;存储过多的相同的key,降低hash table性能;

线程不安全的,想要线程安全,最好的方法是在创建的时候使用下面方法:

  1. Map m = Collections.synchronizedMap(new HashMap(...));

关于迭代器和LinkedList一样!

JDK 1.8 以前 HashMap 的实现是 数组+链表,即使哈希函数取得再好,也很难达到元素百分百均匀分布。

当 HashMap 中有大量的元素都存放到同一个桶中时,这个桶下有一条长长的链表,这个时候 HashMap 就相当于一个单链表,假如单链表有 n 个元素,遍历的时间复杂度就是 O(n),完全失去了它的优势。

针对这种情况,JDK 1.8 中引入了红黑树(查找时间复杂度为 O(logn))来优化这个问题!

二、属性和构造方法:

  1. public class HashMap<K,V> extends AbstractMap<K,V>
  2. implements Map<K,V>, Cloneable, Serializable {
  3.  
  4. private static final long serialVersionUID = 362498820763181265L;
  5.  
  6. /**
  7. * The default initial capacity - MUST be a power of two.
  8. */
  9. //默认初始容量-必须是2的指数。2的4次方=16次方
  10. static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
  11.  
  12. /**
  13. * The maximum capacity, used if a higher value is implicitly specified
  14. * by either of the constructors with arguments.
  15. * MUST be a power of two <= 1<<30.
  16. */
  17. //最大容量,2的30次方=1073741824
  18. static final int MAXIMUM_CAPACITY = 1 << 30;
  19.  
  20. /**
  21. * The load factor used when none specified in constructor.
  22. */
  23. //负载系数=0.75
  24. static final float DEFAULT_LOAD_FACTOR = 0.75f;
  25.  
  26. /**
  27. * The bin count threshold for using a tree rather than list for a
  28. * bin. Bins are converted to trees when adding an element to a
  29. * bin with at least this many nodes. The value must be greater
  30. * than 2 and should be at least 8 to mesh with assumptions in
  31. * tree removal about conversion back to plain bins upon
  32. * shrinkage.
  33. */
  34. //一个桶的树化阈值:8,当桶中元素个数超过这个值时,需要使用红黑树节点替换链表节点
  35. static final int TREEIFY_THRESHOLD = 8;
  36.  
  37. /**
  38. * The bin count threshold for untreeifying a (split) bin during a
  39. * resize operation. Should be less than TREEIFY_THRESHOLD, and at
  40. * most 6 to mesh with shrinkage detection under removal.
  41. */
  42. //一个树的链表还原阈值:6,当扩容时,桶中元素个数小于这个值,就会把树形的桶元素 还原(切分)为链表结构
  43. static final int UNTREEIFY_THRESHOLD = 6;
  44.  
  45. /**
  46. * The smallest table capacity for which bins may be treeified.
  47. * (Otherwise the table is resized if too many nodes in a bin.)
  48. * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
  49. * between resizing and treeification thresholds.
  50. */
  51. //hash表的最小树形化容量:64,1,当哈希表中的容量大于这个值时,表中的桶才能进行树形化;否则桶内元素太多时会扩容,而不是树形化,
    //为了避免进行扩容、树形化选择的冲突,这个值不能小于 4 * TREEIFY_THRESHOLD
  52. static final int MIN_TREEIFY_CAPACITY = 64;
  53.  
  54. static class Node<K,V> implements Map.Entry<K,V> {
  55. final int hash; //对key的hashcode值进行hash运算后得到的值,存储在Entry,避免重复计算
  56. final K key;
  57. V value;
  58. Node<K,V> next; //存储指向下一个Entry的引用,单链表结构
  59.  
  60. Node(int hash, K key, V value, Node<K,V> next) {
  61. this.hash = hash;
  62. this.key = key;
  63. this.value = value;
  64. this.next = next;
  65. }
  66.  
  67. public final K getKey() { return key; }
  68. public final V getValue() { return value; }
  69. public final String toString() { return key + "=" + value; }
  70.  
  71. public final int hashCode() {
  72. return Objects.hashCode(key) ^ Objects.hashCode(value);
  73. }
  74.  
  75. public final V setValue(V newValue) {
  76. V oldValue = value;
  77. value = newValue;
  78. return oldValue;
  79. }
  80.  
  81. public final boolean equals(Object o) {
  82. if (o == this)
  83. return true;
  84. if (o instanceof Map.Entry) {
  85. Map.Entry<?,?> e = (Map.Entry<?,?>)o;
  86. if (Objects.equals(key, e.getKey()) &&
  87. Objects.equals(value, e.getValue()))
  88. return true;
  89. }
  90. return false;
  91. }
  92. }
  93.  
  94. //key的hash值
  95. static final int hash(Object key) {
  96. int h;
  97. return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  98. }
  99.  
  100. /**
  101. * Returns x's Class if it is of the form "class C implements
  102. * Comparable<C>", else null.
  103. */
  104. static Class<?> comparableClassFor(Object x) {
  105. if (x instanceof Comparable) {
  106. Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
  107. if ((c = x.getClass()) == String.class) // bypass checks
  108. return c;
  109. if ((ts = c.getGenericInterfaces()) != null) {
  110. for (int i = 0; i < ts.length; ++i) {
  111. if (((t = ts[i]) instanceof ParameterizedType) &&
  112. ((p = (ParameterizedType)t).getRawType() ==
  113. Comparable.class) &&
  114. (as = p.getActualTypeArguments()) != null &&
  115. as.length == 1 && as[0] == c) // type arg is c
  116. return c;
  117. }
  118. }
  119. }
  120. return null;
  121. }
  122.  
  123. /**
  124. * Returns k.compareTo(x) if x matches kc (k's screened comparable
  125. * class), else 0.
  126. */
  127. @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
  128. static int compareComparables(Class<?> kc, Object k, Object x) {
  129. return (x == null || x.getClass() != kc ? 0 :
  130. ((Comparable)k).compareTo(x));
  131. }
  132.  
  133. /**
  134. * Returns a power of two size for the given target capacity.
  135. */
  136. //返回给定的容量的2的指数
  137. static final int tableSizeFor(int cap) {
  138. int n = cap - 1;
  139. n |= n >>> 1;
  140. n |= n >>> 2;
  141. n |= n >>> 4;
  142. n |= n >>> 8;
  143. n |= n >>> 16;
  144. return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
  145. }
  146.  
  147. /* ---------------- Fields -------------- */
  148.  
  149. /**
  150. * The table, initialized on first use, and resized as
  151. * necessary. When allocated, length is always a power of two.
  152. * (We also tolerate length zero in some operations to allow
  153. * bootstrapping mechanics that are currently not needed.)
  154. */
  155. //初始化数组
  156. transient Node<K,V>[] table;
  157.  
  158. /**
  159. * Holds cached entrySet(). Note that AbstractMap fields are used
  160. * for keySet() and values().
  161. */
  162. transient Set<Map.Entry<K,V>> entrySet;
  163.  
  164. /**
  165. * The number of key-value mappings contained in this map.
  166. */
  167. //实际存储的key-value键值对的个数
  168. transient int size;
  169.  
  170. /**
  171. * The number of times this HashMap has been structurally modified
  172. * Structural modifications are those that change the number of mappings in
  173. * the HashMap or otherwise modify its internal structure (e.g.,
  174. * rehash). This field is used to make iterators on Collection-views of
  175. * the HashMap fail-fast. (See ConcurrentModificationException).
  176. */
  177. transient int modCount;
  178.  
  179. /**
  180. * The next size value at which to resize (capacity * load factor).
  181. *
  182. * @serial
  183. */
  184. // (The javadoc description is true upon serialization.
  185. // Additionally, if the table array has not been allocated, this
  186. // field holds the initial array capacity, or zero signifying
  187. // DEFAULT_INITIAL_CAPACITY.)
  188. //阈值,当table == {}时,该值为初始容量(初始容量默认为16);
  189. //当table被填充了,也就是为table分配内存空间后,threshold一般为 capacity*loadFactory。
  190. int threshold;
  191.  
  192. //负载系数,代表了table的填充度有多少,默认是0.75
  193. final float loadFactor;
  194.  
  195. //创建一个空的HashMap用指定的容量和负载系数
  196. public HashMap(int initialCapacity, float loadFactor) {
  197. if (initialCapacity < 0)
  198. throw new IllegalArgumentException("Illegal initial capacity: " +
  199. initialCapacity);
  200. if (initialCapacity > MAXIMUM_CAPACITY)//不能大于最大值
  201. initialCapacity = MAXIMUM_CAPACITY;
  202. if (loadFactor <= 0 || Float.isNaN(loadFactor))
  203. throw new IllegalArgumentException("Illegal load factor: " +
  204. loadFactor);
  205. this.loadFactor = loadFactor;
  206. this.threshold = tableSizeFor(initialCapacity);
  207. }
  208.  
  209. //创建一个空的HashMap用指定的容量和默认的负载系数(0.75)
  210. public HashMap(int initialCapacity) {
  211. this(initialCapacity, DEFAULT_LOAD_FACTOR);
  212. }
  213.  
  214. //创建一个空的HashMap用默认的容量(16)和默认的负载系数(0.75)
  215. public HashMap() {
  216. this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
  217. }
  218.  
  219. /**
  220. * Constructs a new <tt>HashMap</tt> with the same mappings as the
  221. * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with
  222. * default load factor (0.75) and an initial capacity sufficient to
  223. * hold the mappings in the specified <tt>Map</tt>.
  224. *
  225. * @param m the map whose mappings are to be placed in this map
  226. * @throws NullPointerException if the specified map is null
  227. */
  228. public HashMap(Map<? extends K, ? extends V> m) {
  229. this.loadFactor = DEFAULT_LOAD_FACTOR;
  230. putMapEntries(m, false);
  231. }

三、扩容机制

put方法和resize()方法:

关于扩容的理解可以参考博文 :https://blog.csdn.net/qq_27093465/article/details/52270519

                                                  https://blog.csdn.net/u013494765/article/details/77837338

                                                   https://www.cnblogs.com/chengxiao/p/6059914.html

我理解为什么HashMap的数组长度一定是2的次幂?很大一部分原因是:为了均匀分布table数据和充分利用空间,减少hash冲突,快速查询

  1. /**
  2. * Implements Map.putAll and Map constructor
  3. *
  4. * @param m the map
  5. * @param evict false when initially constructing this map, else
  6. * true (relayed to method afterNodeInsertion).
  7. */
  8. final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
  9. int s = m.size();
  10. if (s > 0) {
  11. if (table == null) { // pre-size 数组是空
  12. float ft = ((float)s / loadFactor) + 1.0F;
  13. int t = ((ft < (float)MAXIMUM_CAPACITY) ?
  14. (int)ft : MAXIMUM_CAPACITY);
  15. if (t > threshold)//大于map的实际可容量就扩大
  16. threshold = tableSizeFor(t);
  17. }
  18. else if (s > threshold)
  19. resize(); //扩容
  20. for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
  21. K key = e.getKey();
  22. V value = e.getValue();
  23. putVal(hash(key), key, value, false, evict);
  24. }
  25. }
  26. }
  27.  
  28. /**
  29. * Associates the specified value with the specified key in this map.
  30. * If the map previously contained a mapping for the key, the old
  31. * value is replaced.
  32. *
  33. * @param key key with which the specified value is to be associated
  34. * @param value value to be associated with the specified key
  35. * @return the previous value associated with <tt>key</tt>, or
  36. * <tt>null</tt> if there was no mapping for <tt>key</tt>.
  37. * (A <tt>null</tt> return can also indicate that the map
  38. * previously associated <tt>null</tt> with <tt>key</tt>.)
  39. */
  40. public V put(K key, V value) {
  41. return putVal(hash(key), key, value, false, true);
  42. }
  43.  
  44. /**
  45. * Implements Map.put and related methods
  46. *
  47. * @param hash hash for key
  48. * @param key the key
  49. * @param value the value to put
  50. * @param onlyIfAbsent if true, don't change existing value
  51. * @param evict if false, the table is in creation mode.
  52. * @return previous value, or null if none
  53. */
  54.  
  55. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  56. boolean evict) {
  57. Node<K,V>[] tab; Node<K,V> p; int n, i;
  58. if ((tab = table) == null || (n = tab.length) == 0) //数组未初始化
  59. n = (tab = resize()).length; //数组设置初始值
  60. if ((p = tab[i = (n - 1) & hash]) == null) //计算脚标i,数组[i]是否是null,(n - 1) & hash计量把数组分布均匀的填满
  61. tab[i] = newNode(hash, key, value, null); //将key,value放到数组[i]
  62. else { //hash冲突时
  63. Node<K,V> e; K k;
  64. if (p.hash == hash &&
  65. ((k = p.key) == key || (key != null && key.equals(k)))) //判断key是否是同一个key
  66. e = p;
  67. else if (p instanceof TreeNode) //如果是tree节点
  68. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  69. else {
  70. for (int binCount = 0; ; ++binCount) {
  71. if ((e = p.next) == null) {
  72. //在链表头部插入key,value
  73. p.next = newNode(hash, key, value, null);
  74. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  75. treeifyBin(tab, hash);
  76. break;
  77. }
  78. if (e.hash == hash &&
  79. ((k = e.key) == key || (key != null && key.equals(k))))
  80. break;
  81. p = e;
  82. }
  83. }
  84. if (e != null) { // existing mapping for key
  85. V oldValue = e.value;
  86. if (!onlyIfAbsent || oldValue == null)
  87. e.value = value;
  88. afterNodeAccess(e);
  89. return oldValue;
  90. }
  91. }
  92. ++modCount;
  93. if (++size > threshold)
  94. resize();
  95. afterNodeInsertion(evict);
  96. return null;
  97. }
  98.  
  99. /**
  100. * Initializes or doubles table size. If null, allocates in
  101. * accord with initial capacity target held in field threshold.
  102. * Otherwise, because we are using power-of-two expansion, the
  103. * elements from each bin must either stay at same index, or move
  104. * with a power of two offset in the new table.
  105. *
  106. * @return the table
  107. */
  108. //以默认容量大小16,默认负载系数0.75为例
  109. final Node<K,V>[] resize() {
  110. Node<K,V>[] oldTab = table;//原数组
  111. int oldCap = (oldTab == null) ? 0 : oldTab.length;//原数组长度 16
  112. int oldThr = threshold;//原临界值 12
  113. int newCap, newThr = 0;
  114. if (oldCap > 0) {
  115. if (oldCap >= MAXIMUM_CAPACITY) {//原数组长度大于最大容量(1073741824)
  116. //则将threshold设为Integer.MAX_VALUE=2147483647,接近MAXIMUM_CAPACITY的两倍
  117. threshold = Integer.MAX_VALUE;
  118. return oldTab;
  119. }
  120. else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && //newCap=32
  121. oldCap >= DEFAULT_INITIAL_CAPACITY)
  122. // 新数组长度 是原数组长度的2倍,
  123. newThr = oldThr << 1; // double threshold 临界值也扩大为原来2倍 24
  124. }
  125. else if (oldThr > 0) // initial capacity was placed in threshold
  126. newCap = oldThr;
  127. else { // zero initial threshold signifies using defaults
  128. newCap = DEFAULT_INITIAL_CAPACITY;
  129. newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
  130. }
  131. if (newThr == 0) {
  132. float ft = (float)newCap * loadFactor;
  133. newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
  134. (int)ft : Integer.MAX_VALUE);
  135. }
  136. threshold = newThr; //新临界值 24
  137. @SuppressWarnings({"rawtypes","unchecked"})
  138. Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; //创建以长度32的新数组
  139. table = newTab;
  140. //如果原来数组有数据,则将原数据复制到新数组中
  141. if (oldTab != null) {
  142. // 根据容量进行循环整个数组,将非空元素进行复制
  143. for (int j = 0; j < oldCap; ++j) {
  144. Node<K,V> e;
  145. // 获取数组的第j个元素
  146. if ((e = oldTab[j]) != null) {
  147. oldTab[j] = null; //原数组j位置置为null,交给GC
  148. // 如果链表只有一个,则进行直接赋值
  149. if (e.next == null)
  150. // e.hash & (newCap - 1) 确定元素存放位置
  151. newTab[e.hash & (newCap - 1)] = e;
  152. else if (e instanceof TreeNode)
  153. ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
  154. else { // preserve order
  155. Node<K,V> loHead = null, loTail = null;
  156. Node<K,V> hiHead = null, hiTail = null;
  157. Node<K,V> next;
  158. do {
  159. next = e.next;
  160. if ((e.hash & oldCap) == 0) {
  161. if (loTail == null)
  162. loHead = e;
  163. else
  164. loTail.next = e;
  165. loTail = e;
  166. }
  167. else {
  168. if (hiTail == null)
  169. hiHead = e;
  170. else
  171. hiTail.next = e;
  172. hiTail = e;
  173. }
  174. } while ((e = next) != null);
  175. if (loTail != null) {
  176. loTail.next = null;
  177. newTab[j] = loHead;
  178. }
  179. if (hiTail != null) {
  180. hiTail.next = null;
  181. newTab[j + oldCap] = hiHead;
  182. }
  183. }
  184. }
  185. }
  186. }
  187. return newTab;
  188. }

剩下的一些方法:

putIfAbsent:value不为空并且不改变现存的值

computeIfAbsent:如果key已存在,返回oldVlaue;不存在创建,返回新创建value

computeIfPresent:如果key不存在,返回null;如果已存在,value为null则删除此节点,不为null替换节点value并返回此value。

compute:如果key不存在,新建key进行存储;如果key存在,value为null则删除此节点,不为null替换节点value并返回此value。

JDK1.8源码hashMap的更多相关文章

  1. 【集合框架】JDK1.8源码分析之HashMap(一) 转载

    [集合框架]JDK1.8源码分析之HashMap(一)   一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Java8的HashMap对之前做了较大的优化 ...

  2. Java源码-HashMap(jdk1.8)

    一.hash方法 如下是jdk1.8中的源码 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = ke ...

  3. JDK1.8源码学习-HashMap

    JDK1.8源码学习-HashMap 目录 一.HashMap简介 HashMap 主要用来存放键值对,它是基于哈希表的Map接口实现的,是常用的Java集合之一. 我们都知道在JDK1.8 之前 的 ...

  4. 【集合框架】JDK1.8源码分析HashSet && LinkedHashSet(八)

    一.前言 分析完了List的两个主要类之后,我们来分析Set接口下的类,HashSet和LinkedHashSet,其实,在分析完HashMap与LinkedHashMap之后,再来分析HashSet ...

  5. 集合之LinkedHashSet(含JDK1.8源码分析)

    一.前言 上篇已经分析了Set接口下HashSet,我们发现其操作都是基于hashMap的,接下来看LinkedHashSet,其底层实现都是基于linkedHashMap的. 二.linkedHas ...

  6. 集合之HashSet(含JDK1.8源码分析)

    一.前言 我们已经分析了List接口下的ArrayList和LinkedList,以及Map接口下的HashMap.LinkedHashMap.TreeMap,接下来看的是Set接口下HashSet和 ...

  7. JDK1.8源码学习-Object

    JDK1.8源码学习-Object 目录 一.方法简介 1.一个本地方法,主要作用是将本地方法注册到虚拟机中. private static native void registerNatives() ...

  8. JDK1.8源码阅读笔记(1)Object类

    JDK1.8源码阅读笔记(1)Object类 ​ Object 类属于 java.lang 包,此包下的所有类在使⽤时⽆需⼿动导⼊,系统会在程序编译期间⾃动 导⼊.Object 类是所有类的基类,当⼀ ...

  9. 【JUC】JDK1.8源码分析之ArrayBlockingQueue(三)

    一.前言 在完成Map下的并发集合后,现在来分析ArrayBlockingQueue,ArrayBlockingQueue可以用作一个阻塞型队列,支持多任务并发操作,有了之前看源码的积累,再看Arra ...

随机推荐

  1. 炸弹人的Alpha版使用说明

    本游戏是一款手机游戏,学生可以在无聊时打发时间,放松心情.现在只有三关,但游戏运行还算可以. 注意事项: 目前游戏还有一些不好的地方,游戏无法暂停,如果游戏任务死亡,则无法重开. 游戏后面的关卡还需要 ...

  2. linq to sql中的自动缓存(对象跟踪)

    linq to sql中,对于同一个DataContext上下文环境,根据表主键选择记录时(当然这里所指的“记录”会自动转成“对象”),如果该记录已经被select过,默认情况下会被自动缓存下来,下次 ...

  3. A-Softmax的总结及与L-Softmax的对比——SphereFace

    A-Softmax的总结及与L-Softmax的对比--SphereFace \(\quad\)[引言]SphereFace在MegaFace数据集上识别率在2017年排名第一,用的A-Softmax ...

  4. OS X(10.10) python3.4 matplotlib的安装

    最近在用python做一些数据处理相关的工作,当然少不了matplotlib这个模块.之前在windows下分分钟安装成功,结果到了mac下死活编译不过去. 最后还是在stackoverflow上找到 ...

  5. numpy教程

    [转]CS231n课程笔记翻译:Python Numpy教程 原文链接:https://zhuanlan.zhihu.com/p/20878530 译者注:本文智能单元首发,翻译自斯坦福CS231n课 ...

  6. 一条sql语句搞定基于mysql的sql执行顺序的基本理解

    对数据库基本操作是每个程序员基本功,如何理解并快速记住sql执行的顺序呢,其实一条复杂的sql就能搞定: SELECT DISTINCT <select_list> FROM <le ...

  7. C#动态对象(dynamic)示例(实现方法和属性的动态)

    C#的动态对象的属性实现比较简单,如果要实现动态语言那种动态方法就比较困难,因为对于dynamic对象,扩展方法,匿名方法都是不能用直接的,这里还是利用对象和委托来模拟这种动态方法的实现,看起来有点J ...

  8. 1643【例 3】Fibonacci 前 n 项和

    1643:[例 3]Fibonacci 前 n 项和 时间限制: 1000 ms         内存限制: 524288 KB sol:这题应该挺水的吧,就像个板子一样 1 0 01 1 0   * ...

  9. Hello 2018 A,B,C,D

    A. Modular Exponentiation time limit per test 1 second memory limit per test 256 megabytes input sta ...

  10. MT【185】$\max$的表示

    已知$f(x)=x^2+(a-4)x+1+|x^2-ax+1|$的最小值为$\dfrac{1}{2}$,则$a$=______ 提示:$f(x)=\max\{2(x-1)^2,2(a-2)x\}$,从 ...