Java 集合 - Map 實現類

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 加鎖是將鎖加載數據分段上 只鎖正在操作的部分數據效率高。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章