The principle of LinkedHashMap

LinkedHashMap Overview

HashMap is disordered, HashMap hash is then put into place in accordance with the corresponding key when put in a hashcode. So in a certain order put into a HashMap, then traverse different now put the order of the HashMap (except when the key has been put hashcode sorted according to the numbers, this probability is very small)

JAVA provides LinkedHashMap after JDK1.4 to help us achieve an orderly HashMap!

LinkedHashMap is a subclass of the HashMap, it retains the order of insertion, when the same required output if the input sequence, then selection LinkedHashMap.

LinkedHashMap hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation provides all of the optional map operations, and allows the use null null values ​​and keys. This class does not guarantee the order of mapping, in particular, it does not guarantee that the order lasts forever.

LinkedHashMap realization differs from HashMap in that, LinkedHashMap maintains a run in the doubly-linked list of all entries. This linked list defines the iteration order, the order may be iterative insertion order or access order.

Note that this implementation is not synchronized. If multiple threads access a hash map link, and at least one of the threads modifies the map structurally, it must be synchronized externally.

The order of elements in the list can be divided into: insertion order of the list, in order of access, and (call get method) of the list. The default is sorted by the insertion order, if you specify the sort order of access, so after calling the get method, the elements of the visit will be moved to the tail of the list, we can continue to access the form sorted in order to access the list.

Small Demo

I was in the very beginning of learning LinkedHashMap, see access sequence, insertion order, and so on, a little dizzy, along with follow-up study in which the principle slowly understand, so I will do during the first few demo to show you the LinkedHashMap use. Understand its effect, then come to study its principles.

HashMap

See the following codes:

public static void main(String[] args) {
    Map<String, String> map = new HashMap<String, String>();
    map.put("apple", "苹果");
    map.put("watermelon", "西瓜");
    map.put("banana", "香蕉");
    map.put("peach", "桃子");

    Iterator iter = map.entrySet().iterator();
    while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
}

A relatively simple test HashMap code through console output, we can see that HashMap is not ordered.

banana=香蕉
apple=苹果
peach=桃子
watermelon=西瓜

LinkedHashMap

We will now map implementation into LinkedHashMap, other code unchanged:Map<String, String> map = new LinkedHashMap<String, String>();

Look at the output console:

apple=苹果
watermelon=西瓜
banana=香蕉
peach=桃子

We can see that the output sequence is completed in accordance with the insertion order! We mentioned above that is to retain the order of insertion. We are not in the above mentioned it can also be sorted according to the access order it? Yes, we use an example to verify:

public static void main(String[] args) {
    Map<String, String> map = new LinkedHashMap<String, String>(16,0.75f,true);
    map.put("apple", "苹果");
    map.put("watermelon", "西瓜");
    map.put("banana", "香蕉");
    map.put("peach", "桃子");

    map.get("banana");
    map.get("apple");

    Iterator iter = map.entrySet().iterator();
    while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }
}

Before the code are similar, but we have more than two lines of code, and initialization time LinkedHashMap, the constructor with not the same, look at the console output:

watermelon=西瓜
peach=桃子
banana=香蕉
apple=苹果

This is what we mentioned before, LinkedHashMap can choose to sort according to Access Order.

LinkedHashMap implementation

For LinkedHashMap, for its inheritance and HashMap ( public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>), the underlying hash table with a doubly linked list to hold all the elements. The basic operation is similar to the parent class HashMap it by overriding parent related methods to achieve their link list of features. Let's analyze LinkedHashMap source code:

Member variables

hash algorithm LinkedHashMap employed and HashMap same, but it redefines stored in the array element Entry, the Entry addition to saving current object references, but also saved on an element before and the next element of after, so that in Kazakhstan Greek table on the basis of the list constitute the two-way link. See the source code:

/**
* The iteration ordering method for this linked hash map: <tt>true</tt>
* for access-order, <tt>false</tt> for insertion-order.
* 如果为true,则按照访问顺序;如果为false,则按照插入顺序。
*/
private final boolean accessOrder;
/**
* 双向链表的表头元素。
 */
private transient Entry<K,V> header;

/**
* LinkedHashMap的Entry元素。
* 继承HashMap的Entry元素,又保存了其上一个元素before和下一个元素after的引用。
 */
private static class Entry<K,V> extends HashMap.Entry<K,V> {
    Entry<K,V> before, after;
    ……
}

LinkedHashMap in integration with the HashMap Entry Entry, but it increases the before and after the reference, refers to a reference element and the next element.

initialization

As can be seen by the source code in the constructor LinkedHashMap, the actual call associated HashMap parent class constructor to construct a table underlying storage array, but additionally may increase this parameter accessOrder, if not set, the default is false, for for insertion order iteration; course be explicitly set to true, representative iterations access order. Such as:

public LinkedHashMap(int initialCapacity, float loadFactor,boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}

We already know LinkedHashMap of Entry elements inherit HashMap of Entry, providing a doubly linked list of functions. In the constructor HashMap, and finally calls the init () method, the associated initialization, this method is not meaningful in the implementation of HashMap, only available to implement the relevant sub-class initialization call.

However, the rewriting LinkedHashMap init () method, after calling the parent class constructor completed structure, to achieve a further initializing operation of its elements Entry.

/**
* Called by superclass constructors and pseudoconstructors (clone,
* readObject) before any entries are inserted into the map.  Initializes
* the chain.
*/
@Override
void init() {
  header = new Entry<>(-1, null, null, null);
  header.before = header.after = header;
}

storage

LinkedHashMap not override the parent class HashMap put method, but a method override sub-put method calls the parent class HashMap void recordAccess (HashMap m), void addEntry (int hash, K key, V value, int bucketIndex) and void createEntry (int hash, K key, V value, int bucketIndex), provides an implementation own unique two-way linked list. In the previous article we have put method of HashMap explained, we are here to re-posted at the source code of the put method of HashMap:

HashMap.put:

public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        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;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
}

Override methods:

void recordAccess(HashMap<K,V> m) {
    LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
    if (lm.accessOrder) {
        lm.modCount++;
        remove();
        addBefore(lm.header);
        }
}

void addEntry(int hash, K key, V value, int bucketIndex) {
    // 调用create方法,将新元素以双向链表的的形式加入到映射中。
    createEntry(hash, key, value, bucketIndex);

    // 删除最近最少使用元素的策略定义
    Entry<K,V> eldest = header.after;
    if (removeEldestEntry(eldest)) {
        removeEntryForKey(eldest.key);
    } else {
        if (size >= threshold)
            resize(2 * table.length);
    }
}

void createEntry(int hash, K key, V value, int bucketIndex) {
    HashMap.Entry<K,V> old = table[bucketIndex];
    Entry<K,V> e = new Entry<K,V>(hash, key, value, old);
    table[bucketIndex] = e;
    // 调用元素的addBrefore方法,将元素加入到哈希、双向链接列表。  
    e.addBefore(header);
    size++;
}

private void addBefore(Entry<K,V> existingEntry) {
    after  = existingEntry;
    before = existingEntry.before;
    before.after = this;
    after.before = this;
}

Read

LinkedHashMap rewrite get HashMap parent class, the actual call to the parent class getEntry () to find the way to get the elements, and then determine when the sorting mode accessOrder is true, recording access sequence, add new elements to access doubly linked list header, and remove it from its original location. Due to the increase in the list, delete a constant level, it does not bring loss of performance.

public V get(Object key) {
    // 调用父类HashMap的getEntry()方法,取得要查找的元素。
    Entry<K,V> e = (Entry<K,V>)getEntry(key);
    if (e == null)
        return null;
    // 记录访问顺序。
    e.recordAccess(this);
    return e.value;
}

void recordAccess(HashMap<K,V> m) {
    LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
    // 如果定义了LinkedHashMap的迭代顺序为访问顺序,
    // 则删除以前位置上的元素,并将最新访问的元素添加到链表表头。  
    if (lm.accessOrder) {
        lm.modCount++;
        remove();
        addBefore(lm.header);
    }
}

/**
* Removes this entry from the linked list.
*/
private void remove() {
    before.after = after;
    after.before = before;
}

/**clear链表,设置header为初始状态*/
public void clear() {
 super.clear();
 header.before = header.after = header;
}

Sort mode

LinkedHashMap accessOrder defined sorting mode, which is a boolean variable attribute, for access order, for the true; insertion sequence, false. Under normal circumstances, you do not have to specify the sort mode, which is the default iteration order of insertion sequence.

These are the default constructor sort mode is designated insertion order. If you want to construct a LinkedHashMap, and intends to press the access from the recent minimum of the order (ie access order) recently visited the most to save the element, then use the Constructor following LinkedHashMap: public LinkedHashMap (int initialCapacity, float loadFactor, boolean accessOrder )

Iteration order the order of hash map is the last visit of its entries, this mapping is suitable for building LRU cache. Providing LinkedHashMap removeEldestEntry (Map.Entry <K, V> eldest) method. This method can provide removed every time you add a new entry procedures for the oldest entry, by default returns false, so, this map will be similar to normal mapping behavior that can never remove the oldest element.

We will introduce LRU cache on how to build a LinkedHashMap detail in a later article.

to sum up

In fact, almost LinkedHashMap HashMap as: Technically, except that it defines a Entry <K, V> header, this header is not on the Table, it is the additional independent out. LinkedHashMap hashMap by inheritance of Entry <K, V>, and add two attributes Entry <K, V> before, after, and combined together to form a header doubly linked list, insertion sort to achieve access order or sequence.

In the course of writing about LinkedHashMap in, remember the interview process before a problem encountered in the implementation may be done in accordance with the iterative insertion order also asked which of my Map? At that time the brain is suddenly short-circuited, but now that I think, can only blame themselves still solid enough to master this knowledge, it is also the code from scratch, carefully read it again.

However, my suggestion is that we first of all need to remember first of all that: LinkedHashMap able to do iterative insertion order or access order, this encounter similar problems in our future development, to think of using LinkedHashMap be addressed, even its internal structure is very understanding, do not use is no use.

The purpose of our study is to better applications.

Guess you like

Origin www.cnblogs.com/baojun/p/11086996.html