Java集合类HashMap源码解析
Note:
HashMap继承自AbstractMap类,实现了Map接口,Cloneable接口,Serializable接口。AbstractMap类是个抽象类,定义了Map最常用的方法,可以看做是接口Map的最小类实现。HashMap是基于哈希表实现的,而另一个Map接口实现类TreeMap是基于红黑树的。
以下是对部分源码的解析:
1 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 初始容量 2 static final int MAXIMUM_CAPACITY = 1 << 30; // 最大容量 3 static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 装载因子,当元素数量为总容量的75%时,需要扩大容量,重散列 4 static final int TREEIFY_THRESHOLD = 8; // 即使用树结构代替链表表示每个桶的阈值数 5 static final int UNTREEIFY_THRESHOLD = 6; // 在resize过程中,不使用树结构的阈值数 6 static final int MIN_TREEIFY_CAPACITY = 64; //
对于每个HashMap中的每个桶有如下定义:
// 静态内部类不能访问外部类的实例成员(因为静态成员不能访问非静态成员)
1 static class Node<K,V> implements Map.Entry<K,V> { // 语法:可以实现接口中的内部接口 2 final int hash; // final的成员变量必须在非静态初始化块,声明该变量,构造器中赋初值 3 final K key; 4 V value; 5 Node<K,V> next; 6 7 Node(int hash, K key, V value, Node<K,V> next) { 8 this.hash = hash; 9 this.key = key; 10 this.value = value; 11 this.next = next; 12 } 13 14 public final K getKey() { return key; } 15 public final V getValue() { return value; } 16 public final String toString() { return key + "=" + value; } 17 18 public final int hashCode() { 19 return Objects.hashCode(key) ^ Objects.hashCode(value);
// 使用Objects.hashCode来计算每个成员的hashCode 20 } 21 22 public final V setValue(V newValue) { 23 V oldValue = value; 24 value = newValue; 25 return oldValue; 26 } 27 28 public final boolean equals(Object o) { 29 if (o == this) 30 return true; 31 if (o instanceof Map.Entry) { 32 Map.Entry<?,?> e = (Map.Entry<?,?>)o; 33 if (Objects.equals(key, e.getKey()) && 34 Objects.equals(value, e.getValue()))
// 使用Objects.equals来比较每个成员 35 return true; 36 } 37 return false; 38 } 39 }
下面是类成员的声明:
1 transient Node<K,V>[] table; // 声明一个表,表的类型是一对(K,V) 2 transient Set<Map.Entry<K,V>> entrySet; // (K,V)对的集合 3 transient int size; // 哈希表中的(K,V)对的个数 4 transient int modCount; // 对哈希表的修改次数 5 int threshold; // 要扩容时元素个数的阈值(capacity * load factor) 6 final float loadFactor; // 装载因子
下面是构造器的定义:
构造器一:
1 public HashMap(int initialCapacity, float loadFactor) { 2 if (initialCapacity < 0) 3 throw new IllegalArgumentException("Illegal initial capacity: " + 4 initialCapacity); 5 if (initialCapacity > MAXIMUM_CAPACITY) 6 initialCapacity = MAXIMUM_CAPACITY; 7 if (loadFactor <= 0 || Float.isNaN(loadFactor)) 8 throw new IllegalArgumentException("Illegal load factor: " + 9 loadFactor); 10 this.loadFactor = loadFactor; 11 this.threshold = tableSizeFor(initialCapacity); 12 }
使用指定的初始容量和装载因子来初始化HashMap,注意源码中会根据用户的initialCapacity将threshold转换成2的幂次大小,下面是tableSizeFor的定义:
1 static final int tableSizeFor(int cap) { 2 int n = cap - 1; 3 n |= n >>> 1; // 无符号右移,高位补0 4 n |= n >>> 2; 5 n |= n >>> 4; 6 n |= n >>> 8; 7 n |= n >>> 16; 8 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; 9 }