HashMap
首先我們看一下類定義的頭部,
繼承了一個抽象的AbstractMap類,實現了3個基本的接口,其中一個是集合接口下的Map接口。
基本的類成員變量如下所示:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;
以及一個內部靜態類
static class Node<K,V> implements Map.Entry<K,V> {...}
先來說一下上面的那些靜態常量的用途,
DEFAULT_INITIAL_CAPACITY 用於表示默認初始化時的map容量大小,這邊是1左移4位,也就是1*2*2*2*2,2的4次,爲16。
MAXIMUM_CAPACITY 表示限定的最大的容量,此處是2的30次
DEFAULT_LOAD_FACTOR 表示默認的填充比(擴展容量的係數),當前爲0.75f
TREEIFY_THRESHOLD 表示一個桶的樹化閾值,當前爲8
UNTREEIFY_THRESHOLD 表示一個樹的鏈表還原閾值(必須比TREEIFY_THRESHOLD 小),當前爲6
MIN_TREEIFY_CAPACITY 表示哈希表的最小樹形化容量
然後接下來就是一個基本的鏈表,靜態內部類
static class Node<K,V> implements Map.Entry<K,V> {}
具體的實現如下所示,就是一個基本的鏈表實現,然後其中多了一個【final int hash】;這個的用途會在後面講到。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
// 計算hash值
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
} //獲取hash值
一個比較函數
/**
* Returns k.compareTo(x) if x matches kc (k's screened comparable
* class), else 0.
* 如果x的類型是kc,返回k.compareTo(x)的比較結果 * 如果x爲空,或者類型不是kc,返回0
*/
@SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
static int compareComparables(Class<?> kc, Object k, Object x) {
return (x == null || x.getClass() != kc ? 0 :
((Comparable)k).compareTo(x));
}
tableSizeFor方法是找到下一個最小的比入參大的2的高次冪。| 這個是按位或,>>>這個是無符號右移(大於輸入參數且最近的2的整數次冪的數)。參考 https://www.cnblogs.com/loading4/p/6239441.html 以及https://zhidao.baidu.com/question/291266003.html
/**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
/**
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
*/
位桶數組,存儲位桶,容量總爲2的冪次
transient Node<K,V>[] table;
/**
* Holds cached entrySet(). Note that AbstractMap fields are used
* for keySet() and values().
*/存儲鍵值對的set
transient Set<Map.Entry<K,V>> entrySet;
/**
* The next size value at which to resize (capacity * load factor).
*
* @serial
*/下一次容量重設(擴容)的臨界值,一般爲2的冪次-1
int threshold;
/**
* The load factor for the hash table.
*
* @serial
*/填充比
final float loadFactor;
接下來是一些公共的方法
首先是4個構造函數
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
HashMap的帶 填充比(loadFactor)的初始化方法,代碼基本簡單直觀
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)//初始容量不能小於0
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
//初始容量不能大於最大容量上限。
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
//填充比不能小於0,不能爲非數字。
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
/**
採用默認填充比的構造函數
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
容量爲16以及採取默認填充比的構造函數
* (16) and the default load factor (0.75).
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
/**
用m的元素去構造hashmap,採用的填充比爲默認的0.75f
*/
public HashMap(Map<? extends K, ? extends V> m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false); //這個方法在下方講解
}
/**
* Implements Map.putAll and Map constructor
*
* @param m the map
* @param evict false when initially constructing this map, else
* true (relayed to method afterNodeInsertion).
將用m的元素全部放入hashmap中,初次構建這個hashmap的時候evict爲false,否則爲true
*/
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
int s = m.size();
if (s > 0) {
if (table == null) { // pre-size
float ft = ((float)s / loadFactor) + 1.0F;
int t = ((ft < (float)MAXIMUM_CAPACITY) ?
(int)ft : MAXIMUM_CAPACITY);
if (t > threshold)
threshold = tableSizeFor(t);
}
else if (s > threshold)
resize();
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
K key = e.getKey();
V value = e.getValue();
putVal(hash(key), key, value, false, evict);
}
}
}
未完待續