Java基礎之集合Map

Map

1. HashMap 是根據數組加單向鏈表來實現的

2. 數組中存儲的就是Node對象

鏈表節點類

    // hash 哈希值
    // key key信息
    // value value信息
    // next 下一個節點
    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() {
            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;
        }
    }

put流程

  1. 調用put(key,value) 方法像map裏添加數據
  2. 根據key生成hashcode,根據hashcode,key,value來創建創建Node節點對象
  3. hashcode和(數組大小(默認初始16)-1)根據‘&’運算得到數組下標位置。所以HashMap是無序的
// 源碼629行
 if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
  1. 如果此下標位置上已經存在Node對象。則根據使用鏈表綁定。(此下標下最後一個節點的next屬性指向此節點的地址)。key的hashcode一致則覆蓋。
// 源碼 641行
  p.next = newNode(hash, key, value, null);
  1. 當數組使用率超過(數組大小*負載因子)時,數組擴容一倍。並數組下的Node節點重新排位。

get流程

  1. 調用get(key)方法
  2. 根據key生成hashcode,hashcode和(數組大小(默認初始16)-1)根據‘&’運算得到數組下標位置。
  3. 根據下標得到數組下的Node節點對象
// 源碼568行
 if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
  1. 如果此節點的key不是我們想要的key,那麼根據此節點next屬性向下查找,一致查找到對的Node節點
  2. 返回此節點的value值

HashMap 和 HashTable 有這樣幾個屬性

threshold:數組大小乘以負載因子得到的值

loadFactor :負載因子(默認0.75)

size: 數組使用率

  1. 數組容量默認16
  2. 負載因子默認0.75
  3. threshold 等於 數組容量乘以負載因子,默認(16 * 0.75 = 12)。
  4. 當put() 時, size 大於 threshold,數組擴容,擴容爲 (原容量 << 1)
  5. 也就是說:(默認)當size大於12時,數組進行擴容至32,threshold變成24。當size大於24時,數組擴容至64,threshold變成48。

HashMap和HashTable有什麼區別

1、HashMap是非線程安全的,HashTable的操作方法都被synchronized修飾所以是線程安全的。

2、HashMap的鍵和值都允許有null值存在,而HashTable則不行。

3、因爲線程安全的問題,HashMap效率比HashTable的要高。

LinkedHashMap

LinkedHashMap裏的屬性
// 第一個(第一個添加的對象的引用)
transient LinkedHashMap.Entry<K,V> head;
// 最後一個(最後一個添加的對象的引用)
transient LinkedHashMap.Entry<K,V> tail;

  1. LinkedHashMap是集成HashMap實現的
  2. LinkedHashMap 重寫了 HashMap的newNode方法,此方法重新創建了node節點。新創建的node節點繼承了HashMap的Node的類,額外還擁有的before(上一個) 和 after(下一個)。而這兩個屬性保證了Map的有序性(雙向鏈表)。

實現過程

  1. 當LinkedHashMap調用put(key,value) 時,會創建Node對象,LinkedHashMap重寫了newNode()和Node類。當創建Node時。

  2. 如果是第一次put就將Node的地址分別賦給head和tail第二次put時,tail(前一個節點對象) 的 after的值設置爲當前創建的對象。當前的對象的before設置爲tail(前一個節點對象),tail的地址在指向當前節點對象。詳細信息看下面代碼

    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
    }

這樣LinkedHashMap 相當於是一個雙向鏈表和HashMap的結合

Map的遍歷

Map<String,String> map = new HashMap<>();
    map.put("name","劉志強");
    map.put("age","24");
        
    map.forEach((k,v)-> System.out.println(k + ":" + v));
    // 或者(jdk1.8生效)
    Set<Map.Entry<String, String>> set =  map.entrySet();

    
    Iterator<Map.Entry<String, String>> value = set.iterator();
    while (value.hasNext()) {
        Map.Entry s = value.next();
        System.out.println(s.getKey() + ":" + s.getValue());
    }

TreeMap

TreeMap中的元素默認按照keys的自然排序排列。

(對Integer來說,其自然排序就是數字的升序;對String來說,其自然排序就是按照字母表排序)

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