MapClassDiagram

  

Map

(1)维护key-value 之间的映射,key不可以重复。

(2)提供三个视图:EntryKey,Values,EntrySet

(3)map自身不能做为key,put到自身的map中。但可以作为value。

(4)使用Entry来存放Key-Value

AbstractMap

(1)Clone:浅拷贝

(2)两个Map.Entry实现SimpleEntry,SimpleImmutableEntry(不可改变Entry)

     Map实现类中都有自己Map.Entry实现。

HashMap

(1)存储结构:数组+链表(哈希表+链表处理冲突),允许key为Null,浅拷贝

 

(2)Default Size=16,Default Load Factor=0.75. 可以在构造map时指定。

(3)transient Entry[], transient Size. 自己拥有WriteObject和ReadObject方法。

(4)capacity永远是2的倍数。

(5)HashMap.Entry 存放四个值:

        final K key;

        V value;

        Entry<K,V> next;

        final int hash;

(6)Null Key:

    如果Key 为Null 则key的hash值为0,进而index值为0。

(7)get过程:参数key

          public V get(Object key) {

        if (key == null)

           //如果key为Null, 则在table[0]处进行查找。

            return getForNullKey();

        //如果key不为Null

        int hash = hash(key.hashCode());

       //计算hash值和index, 在table[index]下进行查找。

        for (Entry<K,V> e = table[indexFor(hash, table.length)];

             e != null;

             e = e.next) {

            Object k;

           //比较hash值和key值,如果都相同则返回value。

            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))

                return e.value;

        }

        return null;

}

 

 

private V getForNullKey() {

//key 为Null, index 为0.

        for (Entry<K,V> e = table[0]; e != null; e = e.next) {

            if (e.key == null)

                return e.value;

        }

        return null;

    }

 

 

 

 (8)put过程:

 

  public V put(K key, V value) {

        if (key == null)

           //如果key为Null

            return putForNullKey(value);

       //key 不为Null

        //计算hash,index

        int hash = hash(key.hashCode());

        int i = indexFor(hash, table.length);

       //如果key已经存在则进行替换,返回之前的值。

        for (Entry<K,V> e = table[i]; e != null; e = e.next) {

            Object k;

            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

                V oldValue = e.value;

                e.value = value;

                e.recordAccess(this);

                return oldValue;

            }

        }

       //如果key不存在,则添加。

        modCount++;

        addEntry(hash, key, value, i);

        return null;

}

//put for Null key

private V putForNullKey(V value) {

    //在table[0]的位置进行查找,存在更新值,不存在则添加。

        for (Entry<K,V> e = table[0]; e != null; e = e.next) {

            if (e.key == null) {

                V oldValue = e.value;

                e.value = value;

                e.recordAccess(this);

                return oldValue;

            }

        }

        modCount++;

        addEntry(0, null, value, 0);

        return null;

    }

//添加使用“头插法”,将新插入Entry放在table[index]的位置。

    void addEntry(int hash, K key, V value, int bucketIndex) {

    Entry<K,V> e = table[bucketIndex];

        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);

        if (size++ >= threshold)

           //如果size大于阀值,扩充table容量。

            resize(2 * table.length);

}

 

 

(9)Resize 过程

 

   void resize(int newCapacity) {

        Entry[] oldTable = table;

        int oldCapacity = oldTable.length;

       //如果当前capacity已经是最大值,则将阀值改为最大值

        if (oldCapacity == MAXIMUM_CAPACITY) {

            threshold = Integer.MAX_VALUE;

            return;

        }

       //创建新的table

        Entry[] newTable = new Entry[newCapacity];

       //将原table中的值重新定位到新的table当中。

        transfer(newTable);

       //更新现有引用,并计算阀值

        table = newTable;

        threshold = (int)(newCapacity * loadFactor);

}

 

    void transfer(Entry[] newTable) {

        Entry[] src = table;

        int newCapacity = newTable.length;

        for (int j = 0; j < src.length; j++) {

            Entry<K,V> e = src[j];

            if (e != null) {

                src[j] = null;

                do {

                    Entry<K,V> next = e.next;

                  //重新定位index

                    int i = indexFor(e.hash, newCapacity);

                  //头插法插入新table

                    e.next = newTable[i];

                    newTable[i] = e;

                    e = next;

                } while (e != null);

            }

        }

  }

 

 

(10)Remove 过程

final Entry<K,V> removeEntryForKey(Object key) {

    //计算hash值和index

        int hash = (key == null) ? 0 : hash(key.hashCode());

        int i = indexFor(hash, table.length);

       //找到要遍历查找的链表头元素

        Entry<K,V> prev = table[i];

        Entry<K,V> e = prev;

 

        while (e != null) {

            Entry<K,V> next = e.next;

            Object k;

            if (e.hash == hash &&

                ((k = e.key) == key || (key != null && key.equals(k)))) {

                modCount++;

                size--;

                if (prev == e)

                 //如果删除的是头元素

                    table[i] = next;

                else

                 //从链表中删除

                    prev.next = next;

                e.recordRemoval(this);

                return e;

            }

           //向后推移

            prev = e;

            e = next;

        }

 

        return e;

    }

 

LinkedHashMap

  LinkedHashMap在HashMap的基础上进行封装,将entry按照插入顺序链接起来,形成双向链表。

(1) LinkedHashMap.Entry 继承了HashMap.Entry 添加了before和after指针(指向LinkedHashMap.entry)。

    private static class Entry<K,V> extends HashMap.Entry<K,V> {

        // These fields comprise the doubly linked list used for iteration.

        Entry<K,V> before, after;

       //给HashMap.Entry赋值。

    Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {

            super(hash, key, value, next);

        }

  }

 

(2)accessOrder:来确定按照何种顺序进行访问。

a)   access-order: from least-recently accessed to most-recently. 适合使用LRU算法。(按照最近访问顺序,从最近最少使用到最近最多使用)

        void recordAccess(HashMap<K,V> m) {

            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;

            if (lm.accessOrder) {

                lm.modCount++;

              //从链表中移除

                remove();

              //添加到链表尾部。

                addBefore(lm.header);

            }}

 

b)   insertion-order:插入顺序。

(3)重写了transfer方法,是的resize的性能提高。

    void transfer(HashMap.Entry[] newTable) {

        int newCapacity = newTable.length;

       //使用链表进行迭代。

        for (Entry<K,V> e = header.after; e != header; e = e.after) {

            int index = indexFor(e.hash, newCapacity);

            e.next = newTable[index];

            newTable[index] = e;

        }

}

 

 

同理其它在HashMap中需要迭代的地方都使用链表进行迭代。如containsValue,KeyIterator, ValueIterator, EntryIterator等。

(4)添加Entry的时候会调用addBefore(header)方法,建立链表关系。

        private void addBefore(Entry<K,V> existingEntry) {

           //实际existing就是指header

            after  = existingEntry;

            before = existingEntry.before;

            before.after = this;

            after.before = this;

        }

 

(5)删除时同样会删除链表关系。

        private void remove() {

            before.after = after;

            after.before = before;

        }