1 package MyHashMap; 2 3 import java.io.IOException; 4 import java.io.InvalidObjectException; 5 import java.io.Serializable; 6 import java.lang.reflect.ParameterizedType; 7 import java.lang.reflect.Type; 8 import java.util.*; 9 import java.util.function.BiConsumer; 10 import java.util.function.BiFunction; 11 import java.util.function.Consumer; 12 import java.util.function.Function; 13 import sun.misc.SharedSecrets; 14 15 16 17 public class HashMap<K,V> extends AbstractMap<K,V> 18 implements Map<K,V>, Cloneable, Serializable { 19 20 private static final long serialVersionUID = 362498820763181265L; 21 22 23 /** 24 * 默認初始容量-必須是2的冪。 25 */ 26 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 27 28 29 30 /** 31 * 最大容量。 32 *必須是2的冪<=1<<30。 33 */ 34 static final int MAXIMUM_CAPACITY = 1 << 30; 35 36 /** 37 * 構造函數中未指定時使用的加載因子。 38 */ 39 static final float DEFAULT_LOAD_FACTOR = 0.75f; 40 41 /** 42 * 使用樹而不是數組作爲儲存數據的閾(yu)值 43 * 數組將轉換爲紅黑樹該值必須大於2,並且至少應爲8, 44 */ 45 static final int TREEIFY_THRESHOLD = 8; 46 47 /** 48 * 在哈希表擴容時,如果發現鏈表長度小於 6,則會由樹重新退化爲鏈表 49 */ 50 static final int UNTREEIFY_THRESHOLD = 6; 51 52 /** 53 * 在轉變成樹之前,還會有一次判斷,只有鍵值對數量大於 64 纔會發生轉換。 54 * 這是爲了避免在哈希表建立初期,多個鍵值對恰好被放入了同一個鏈表中而導致不必要的轉化 55 */ 56 static final int MIN_TREEIFY_CAPACITY = 64; 57 58 /** 59 * 當數組節點超過 TREEIFY_THRESHOLD 閾值時使用(有關TreeNode子類的信息,請參見下文,有關Entry子類的信息,請參見LinkedHashMap。) 60 * 61 * 該類爲靜態內部類,hashMap使用靜態內部類創建鏈表 62 */ 63 static class Node<K,V> implements Map.Entry<K,V> { 64 final int hash; 65 final K key; 66 V value; 67 Node<K,V> next; 68 69 Node(int hash, K key, V value, Node<K,V> next) { 70 this.hash = hash; 71 this.key = key; 72 this.value = value; 73 this.next = next; 74 } 75 76 public final K getKey() { return key; } 77 public final V getValue() { return value; } 78 public final String toString() { return key + "=" + value; } 79 80 public final int hashCode() { 81 return Objects.hashCode(key) ^ Objects.hashCode(value); 82 } 83 84 public final V setValue(V newValue) { 85 V oldValue = value; 86 value = newValue; 87 return oldValue; 88 } 89 90 public final boolean equals(Object o) { 91 if (o == this) 92 return true; 93 if (o instanceof Map.Entry) { 94 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 95 if (Objects.equals(key, e.getKey()) && 96 Objects.equals(value, e.getValue())) 97 return true; 98 } 99 return false; 100 } 101 } 102 103 /* ---------------- Static utilities -------------- */ 104 105 /** 106 * 計算key的hash值 107 * >>表示右移,如果該數爲正,則高位補0,若爲負數,則高位補1; 108 * >>>表示無符號右移,也叫邏輯右移,即若該數爲正,則高位補0,而若該數爲負數,則右移後高位同樣補0。 109 * 使用key的hash值與該hash值右移16位異或 110 * 異或的定義,兩個數的二進制表示進行按位異或,相同爲0 , 相異爲1, 111 */ 112 static final int hash(Object key) { 113 int h; 114 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); 115 } 116 117 /** 118 * 如果x的類型實現Comparable<T> 返回x的 Class<?> 119 * 如果不是返回 null 120 */ 121 static Class<?> comparableClassFor(Object x) { 122 if (x instanceof Comparable) { 123 Class<?> c; Type[] ts, as; Type t; ParameterizedType p; 124 if ((c = x.getClass()) == String.class) // 將x.getClass() 賦值給c 125 return c; 126 if ((ts = c.getGenericInterfaces()) != null) { 127 for (int i = 0; i < ts.length; ++i) { 128 if (((t = ts[i]) instanceof ParameterizedType) && 129 ((p = (ParameterizedType)t).getRawType() == 130 Comparable.class) && 131 (as = p.getActualTypeArguments()) != null && 132 as.length == 1 && as[0] == c) // type arg is c 133 return c; 134 } 135 } 136 } 137 return null; 138 } 139 140 141 public static void main(String[] args) { 142 int n = 33 - 1; 143 System.out.println(Integer.toBinaryString(n)); 144 n |= n >>> 1; 145 System.out.println(Integer.toBinaryString(n)); 146 n |= n >>> 2; 147 System.out.println(Integer.toBinaryString(n)); 148 n |= n >>> 4; 149 System.out.println(Integer.toBinaryString(n)); 150 n |= n >>> 8; 151 System.out.println(Integer.toBinaryString(n)); 152 n |= n >>> 16; 153 System.out.println(n); 154 } 155 156 /** 157 * Returns k.compareTo(x) if x matches kc (k's screened comparable 158 * class), else 0. 159 */ 160 @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable 161 static int compareComparables(Class<?> kc, Object k, Object x) { 162 return (x == null || x.getClass() != kc ? 0 : 163 ((Comparable)k).compareTo(x)); 164 } 165 166 /** 167 * 對於給定的目標容量,返回兩倍大小的冪。 168 */ 169 static final int tableSizeFor(int cap) { 170 int n = cap - 1; //保證容量值輸入爲2的冪時不會被再次擴容2倍 int n = 33 - 1; 100000 171 n |= n >>> 1;// 110000 n 與 n邏輯右移1位 賦值給n 目標爲:把二進制數的所有位都變成1 172 // 1移1位與運算變成兩個1 ,兩個1移兩位變成4個 4個變成8個 8個變16個 16個變32 覆蓋所有的數 完成擴容。完美!!! 173 n |= n >>> 2;//111100 .... 174 n |= n >>> 4;//111111 ..... 175 n |= n >>> 8;//111111 176 n |= n >>> 16;//111111 177 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; 178 } 179 180 /* ---------------- Fields -------------- */ 181 182 /** 183 * transient修飾符的作用是使該變量在序列化的時候不會被儲存。 184 * table是儲存了容器中所有的元素(地址) 185 * HashMap的哈希桶數組,非常重要的存儲結構,用於存放表示鍵值對數據的Node元素。 186 */ 187 transient Node<K,V>[] table; 188 189 /** 190 * HashMap將數據轉換成set的另一種存儲形式,這個變量主要用於迭代功能。 191 */ 192 transient Set<Map.Entry<K,V>> entrySet; 193 194 /** 195 * HashMap中實際存在的Node數量,注意這個數量不等於table的長度, 196 * 甚至可能大於它,因爲在table的每個節點上是一個鏈表(或RBT)結構,可能不止有一個Node元素存在。 197 */ 198 transient int size; 199 200 /** 201 * HashMap的數據被修改的次數,這個變量用於迭代過程中的Fail-Fast機制, 202 * 其存在的意義在於保證發生了線程安全問題時,能及時的發現(操作前備份的count和當前modCount不相等)並拋出異常終止操作。 203 */ 204 transient int modCount; 205 206 /** 207 * The next size value at which to resize (capacity * load factor). 208 *HashMap的擴容閾值,在HashMap中存儲的Node鍵值對超過這個數量時,自動擴容容量爲原來的二倍。 209 * @serial 210 */ 211 // (The javadoc description is true upon serialization. 212 // Additionally, if the table array has not been allocated, this 213 // field holds the initial array capacity, or zero signifying 214 // DEFAULT_INITIAL_CAPACITY.) 215 int threshold; 216 217 /** 218 * HashMap的負載因子,可計算出當前table長度下的擴容閾值:threshold = loadFactor * table.length。 219 * 220 * @serial 221 */ 222 final float loadFactor; 223 224 /* ---------------- Public operations -------------- */ 225 226 /** 227 *hashMap的構造器, 228 * @param initialCapacity 初始化大小容量 默認16 229 * @param loadFactor 負載因子 默認0.75 230 * @throws IllegalArgumentException if the initial capacity is negative 231 * or the load factor is nonpositive 232 */ 233 public HashMap(int initialCapacity, float loadFactor) { 234 if (initialCapacity < 0) 235 throw new IllegalArgumentException("Illegal initial capacity: " + 236 initialCapacity); 237 if (initialCapacity > MAXIMUM_CAPACITY)//如果初始容量大於最大容量 則=最大容量 238 initialCapacity = MAXIMUM_CAPACITY; 239 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 240 throw new IllegalArgumentException("Illegal load factor: " + 241 loadFactor); 242 this.loadFactor = loadFactor;//賦值負載因子 243 this.threshold = tableSizeFor(initialCapacity);//把容量轉爲範圍內最大2的冪賦值給擴容閾值 244 } 245 246 /** 247 * Constructs an empty <tt>HashMap</tt> with the specified initial 248 * capacity and the default load factor (0.75). 249 * 250 * @param initialCapacity the initial capacity. 251 * @throws IllegalArgumentException if the initial capacity is negative. 252 */ 253 public HashMap(int initialCapacity) { 254 this(initialCapacity, DEFAULT_LOAD_FACTOR); 255 } 256 257 /** 258 * Constructs an empty <tt>HashMap</tt> with the default initial capacity 259 * (16) and the default load factor (0.75). 260 */ 261 public HashMap() { 262 this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted 263 } 264 265 /** 266 * Constructs a new <tt>HashMap</tt> with the same mappings as the 267 * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with 268 * default load factor (0.75) and an initial capacity sufficient to 269 * hold the mappings in the specified <tt>Map</tt>. 270 * 271 * @param m the map whose mappings are to be placed in this map 272 * @throws NullPointerException if the specified map is null 273 */ 274 public HashMap(Map<? extends K, ? extends V> m) { 275 this.loadFactor = DEFAULT_LOAD_FACTOR; 276 putMapEntries(m, false); 277 } 278 279 /** 280 * Implements Map.putAll and Map constructor 281 * putALL 方法 把map添加到當前map中。 282 * 283 * @param m the map 284 * @param evict false when initially constructing this map, else 285 * true (relayed to method afterNodeInsertion). 286 */ 287 final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { 288 int s = m.size(); 289 if (s > 0) { 290 if (table == null) { //如果map的容器是空的,沒有初始化 291 float ft = ((float)s / loadFactor) + 1.0F; // threshold = loadFactor * table.length。計算容器需要的大小 292 int t = ((ft < (float)MAXIMUM_CAPACITY) ? 293 (int)ft : MAXIMUM_CAPACITY); 294 if (t > threshold)//如果容器大小大於當前的擴容閾值,則閾值擴容爲範圍內最大2的冪 295 threshold = tableSizeFor(t); 296 } 297 else if (s > threshold)//如果table 不爲 null 且 傳入的map的大小大於當前的擴容閾值 298 resize();//table 擴容 299 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {//給table賦值, 就是put操作 300 K key = e.getKey(); 301 V value = e.getValue(); 302 putVal(hash(key), key, value, false, evict);// put操作 303 } 304 } 305 }
HashMap 超詳細註釋解讀