HashMap
HashMap 類和 Hashtable 非常的類似,除了它是線程不安全的和允許 key 和 value 的 null 值。
紅黑樹介紹
紅黑樹(Red Black Tree)是一種自平衡二叉查找樹,在進行插入和刪除操作時通過特定操作保持二叉查找樹的平衡,從而獲得較高的查找性能。
性質1. 結點是紅色或黑色。
性質2. 根結點是黑色。
性質3. 所有葉子都是黑色。(葉子是NIL結點)
性質4. 每個紅色結點的兩個子結點都是黑色。
性質5. 從任一結點到其每個葉子的所有路徑都包含相同數目的黑色結點。
Node 內部類
每一對鍵值對,都對應一個唯一的 Node 對象。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next; // key 衝突的時候使用
}
加載因子
用來計算擴容的閾值,不需要我們改變,默認就好。
this.loadFactor = 0.75f;
默認容量
默認容量 16,必須是 2 的幾次方的值。
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 16
默認閾值
閾值 = 容量 * 加載因子
int threshold;
存放 Node
transient Node<K,V>[] table;
構造方法
public HashMap(int initialCapacity, float loadFactor) {
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
// 當你傳入 17,返回是 32。
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;
}
putVal 方法
final V putVal(K key, V value, boolean onlyIfAbsent, boolean evict) {
// 擾動
int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
Node<K,V>[] tab; Node<K,V> p; int n, i;
// 使用一個局部變量指向全局變量,可以提升代碼性能;
if ((tab = table) == null || (n = tab.length) == 0)
// 初始化數組
n = (tab = resize()).length;
// 數組位置 i 沒有值的時候
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
// hash 衝突
else {
Node<K,V> e; K k;
// 存在相同的 key
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 是紅黑樹的節點情況
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // 8
treeifyBin(tab, hash); // 樹化
break;
}
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // 存在映射
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
HashTable 和 HashMap
1、Hashtable 是不允許鍵或值爲 null 的,HashMap 的鍵值則都可以爲 null。
2、hash 值算法不同:HashMap添加元素時,是使用自定義的哈希算法,而HashTable是直接採用 key 的 hashCode。
3、Hashtable 繼承的是 Dictionary類,而 HashMap 繼承的是 AbstractMap 類。
4、HashMap 的初始容量爲:16,Hashtable 初始容量爲:11,兩者的負載因子默認都是:0.75。
5、HashMap 擴容規則爲當前容量翻倍,Hashtable 擴容規則爲當前容量翻倍 +1。
6、 Hashtable 是同步(synchronized)的,適用於多線程環境,而 HashMap 不是同步的,適用於單線程環境。
ConcurrentMap 和 HashMap
1、HashMap:數組 + 鏈表 + 紅黑樹,非線程安全。
2、ConcurrentMap:數據結構:分段數組 + 鏈表 + 紅黑樹,線程安全。
3、ConcurrentMap 加鎖是將鎖加載數據分段上 只鎖正在操作的部分數據效率高。