/** |
|
* HashMap是常用的Java集合之一,是基于哈希表的Map接口的实现。与HashTable主要区别为不支持同步和允许null作为key和value。 |
|
* HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。 |
|
* 如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。 |
|
* 在JDK1.6中,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。 |
|
* 但是当位于一个数组中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。 |
|
* 而JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值8时,将链表转换为红黑树,这样大大减少了查找时间。 |
|
* 原本Map.Entry接口的实现类Entry改名为了Node。转化为红黑树时改用另一种实现TreeNode。 |
|
*/ |
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 /**
8 * 默认的初始容量(容量为HashMap中槽的数目)是16,且实际容量必须是2的整数次幂。
9 */
10 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
11
12 /**
13 * 最大容量(必须是2的幂且小于2的30次方,传入容量过大将被这个值替换)
14 */
15 static final int MAXIMUM_CAPACITY = 1 << 30;
16
17 /**
18 * 默认装填因子0.75,如果当前键值对个数 >= HashMap最大容量*装填因子,进行rehash操作
19 */
20 static final float DEFAULT_LOAD_FACTOR = 0.75f;
21 /**
22 * JDK1.8 新加,Entry链表最大长度,当桶中节点数目大于该长度时,将链表转成红黑树存储;
23 */
24 static final int TREEIFY_THRESHOLD = 8;
25
26 /**
27 * JDK1.8 新加,当桶中节点数小于该长度,将红黑树转为链表存储;
28 */
29 static final int UNTREEIFY_THRESHOLD = 6;
30
31 /**
32 * 桶可能被转化为树形结构的最小容量。当哈希表的大小超过这个阈值,才会把链式结构转化成树型结构,否则仅采取扩容来尝试减少冲突。
33 * 应该至少4*TREEIFY_THRESHOLD来避免扩容和树形结构化之间的冲突。
34 */
35 static final int MIN_TREEIFY_CAPACITY = 64;
36
37 /**
38 * JDK1.6用Entry描述键值对,JDK1.8中用Node代替Entry
39 */
40 static class Node<K, V> implements Map.Entry<K, V> {
41 // hash存储key的hashCode
42 final int hash;
43 // final:一个键值对的key不可改变
44 final K key;
45 V value;
46 //指向下个节点的引用
47 Node<K, V> next;
48
49 //构造函数
50 Node(int hash, K key, V value, Node<K, V> next) {
51 this.hash = hash;
52 this.key = key;
53 this.value = value;
54 this.next = next;
55 }
56
57 public final K getKey() {
58 return key;
59 }
60
61 public final V getValue() {
62 return value;
63 }
64
65 public final String toString() {
66 return key + "=" + value;
67 }
68
69 public final int hashCode() {
70 return Objects.hashCode(key) ^ Objects.hashCode(value);
71 }
72
73 public final V setValue(V newValue) {
74 V oldValue = value;
75 value = newValue;
76 return oldValue;
77 }
78 public final boolean equals(Object o) {
79 if (o == this)
80 return true;
81 if (o instanceof Map.Entry) {
82 Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
83 if (Objects.equals(key, e.getKey()) &&
84 Objects.equals(value, e.getValue()))
85 return true;
86 }
87 return false;
88 }
89 }
/** |
|
* HashMap中键值对的存储形式为链表节点,hashCode相同的节点(位于同一个桶)用链表组织 |
|
* hash方法分为三步: |
|
* 1.取key的hashCode |
|
* 2.key的hashCode高16位异或低16位 |
|
* 3.将第一步和第二步得到的结果进行取模运算。 |
|
*/ |
1 static final int hash(Object key) {
2 int h;
3 //计算key的hashCode, h = Objects.hashCode(key)
4 //h >>> 16表示对h无符号右移16位,高位补0,然后h与h >>> 16按位异或
5 return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
6 }
7
8 /**
9 * 如果参数x实现了Comparable接口,返回参数x的类名,否则返回null
10 */
11 static Class<?> comparableClassFor(Object x) {
12 if (x instanceof Comparable) {
13 Class<?> c;
14 Type[] ts, as;
15 Type t;
16 ParameterizedType p;
17 if ((c = x.getClass()) == String.class) // bypass checks
18 return c;
19 if ((ts = c.getGenericInterfaces()) != null) {
20 for (int i = 0; i < ts.length; ++i) {
21 if (((t = ts[i]) instanceof ParameterizedType) &&
22 ((p = (ParameterizedType) t).getRawType() ==
23 Comparable.class) &&
24 (as = p.getActualTypeArguments()) != null &&
25 as.length == 1 && as[0] == c) // type arg is c
26 return c;
27 }
28 }
29 }
30 return null;
31 }
32
33 /**
34 * 如果x的类型为kc,则返回k.compareTo(x),否则返回0
35 */
36 @SuppressWarnings({"rawtypes", "unchecked"}) // for cast to Comparable
37 static int compareComparables(Class<?> kc, Object k, Object x) {
38 return (x == null || x.getClass() != kc ? 0 :
39 ((Comparable) k).compareTo(x));
40 }
41
42 /**
43 * 结果为>=cap的最小2的自然数幂
44 */
45 static final int tableSizeFor(int cap) {
46 //先移位再或运算,最终保证返回值是2的整数幂
47 int n = cap - 1;
48 n |= n >>> 1;
49 n |= n >>> 2;
50 n |= n >>> 4;
51 n |= n >>> 8;
52 n |= n >>> 16;
53 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
54 }
/* ---------------- Fields -------------- */ |
1 /**
2 * 哈希桶数组,分配的时候,table的长度总是2的幂
3 */
4 transient Node<K, V>[] table;
5
6 /**
7 * HashMap将数据转换成set的另一种存储形式,这个变量主要用于迭代功能
8 */
9 transient Set<Map.Entry<K, V>> entrySet;
10
11 /**
12 * 实际存储的数量,则HashMap的size()方法,实际返回的就是这个值,isEmpty()也是判断该值是否为0
13 */
14 transient int size;
15
16 /**
17 * hashmap结构被改变的次数,fail-fast机制
18 */
19 transient int modCount;
20
21 /**
22 * HashMap的扩容阈值,在HashMap中存储的Node键值对超过这个数量时,自动扩容容量为原来的二倍
23 *
24 * @serial
25 */
26 int threshold;
27
28 /**
29 * HashMap的负加载因子,可计算出当前table长度下的扩容阈值:threshold = loadFactor * table.length
30 *
31 * @serial
32 */
33 final float loadFactor;
具体源码参考地址:
https://github.com/wupeixuan/JDKSourceCode1.8/blob/master/src/java/util/HashMap.java