hashMap 源碼註釋分析(一)

  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 超詳細註釋解讀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章