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 超详细注释解读

posted @ 2019-11-27 18:08  你说累不累  阅读(338)  评论(0编辑  收藏  举报