Read LinkedHashMap source code

//LinkedHashMap inherits HashMap, which maintains an insertion order compared to HashMap. LinkedHashMap and HashMap are also the embodiment of a template design pattern
// first look at the constructor
public LinkedHashMap() {
        super();
	//The sorting rule false is read in the insertion order, and the true least recently used can be used for LRU (Least Recently Used) cache
        accessOrder = false;
    }

public LinkedHashMap(int initialCapacity) {
        super(initialCapacity);
        accessOrder = false;
    }

public LinkedHashMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        accessOrder = false;
    }

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

public LinkedHashMap(Map<? extends K, ? extends V> m) {
        super(m);
        accessOrder = false;
    }

//Override the init hook method in HashMap.
 void init() {
        header = new Entry<>(-1, null, null, null);
        header.before = header.after = header;
    }

//When adding, the method of the parent class will be called
public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        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;
		//This code is the key, this is also a hook method. Execute the recordAccess method in LinkedHashMap.
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
	//This sentence is overwritten again
        addEntry(hash, key, value, i);
        return null;
    }

  void recordAccess(HashMap<K,V> m) {
            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
	    //If it is LRU mode
            if (lm.accessOrder) {
                lm.modCount++;
		// delete itself
                remove();
		//In re-adding yourself to the queue, so that headed.after is always the least commonly used in the queue.
                addBefore(lm.header);
            }
        }

private void remove() {
            before.after = after;
            after.before = before;
        }


//This method is called when remove() is called
void recordRemoval(HashMap<K,V> m) {
            remove();
        }

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

        // Remove eldest entry if instructed
        Entry<K,V> eldest = header.after;
	//If you need to delete the element with the longest survival time
        if (removeEldestEntry(eldest)) {
            removeEntryForKey(eldest.key);
        }
    }

// also override the method of the parent class
void createEntry(int hash, K key, V value, int bucketIndex) {
      1  HashMap.Entry<K,V> old = table[bucketIndex];
      2  Entry<K,V> e = new Entry<>(hash, key, value, old);
      3  table[bucketIndex] = e;
         Steps 1, 2, 3 and the operation of HashMap have been
	 
        e.addBefore(header);
        size++;
    }

//This overrides the element migration of the parent class during expansion
void transfer(HashMap.Entry[] newTable, boolean rehash) {
        int newCapacity = newTable.length;
	//Starting from the header bidirectional list is faster and more efficient than the original transfer directly from entry[]
        for (Entry<K,V> e = header.after; e != header; e = e.after) {
            if (rehash)
                e.hash = (e.key == null) ? 0 : hash(e.key);
            int index = indexFor(e.hash, newCapacity);
            e.next = newTable[index];
            newTable[index] = e;
        }
    }
//Construct a doubly linked list to insert elements in front of head and behind head.before, that is, insert them in order
 private void addBefore(Entry<K,V> existingEntry) {
            after  = existingEntry;
            before = existingEntry.before;
            before.after = this;
            after.before = this;
        }


//get element
public V get(Object key) {
        Entry<K,V> e = (Entry<K,V>)getEntry(key);
        if (e == null)
            return null;
        e.recordAccess(this);
        return e.value;
    }

//return to initial state
 public void clear() {
        super.clear();
        header.before = header.after = header;
    }
 
 //Re-override the containsValue method and it is more efficient to traverse directly from the header
 public boolean containsValue(Object value) {
        // Overridden to take advantage of faster iterator

        if (value==null) {
            for (Entry e = header.after; e != header; e = e.after)
                if (e.value==null)
                    return true;
        } else {
            for (Entry e = header.after; e != header; e = e.after)
                if (value.equals(e.value))
                    return true;
        }
        return false;
    }

//Override the newEntryIterator method when calling map.entry traversal.
Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }

private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() { return nextEntry(); }
    }

private abstract class LinkedHashIterator<T> implements Iterator<T> {
        Entry<K,V> nextEntry    = header.after;
        Entry<K,V> lastReturned = null;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         */
        int expectedModCount = modCount;

        public boolean hasNext() {
            return nextEntry! = header;
        }

        public void remove() {
            if (lastReturned == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            LinkedHashMap.this.remove(lastReturned.key);
            lastReturned = null;
            expectedModCount = modCount;
        }
       // Traverse one by one from the head so that the FIFO order is guaranteed
        Entry <K, V> nextEntry () {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (nextEntry == header)
                throw new NoSuchElementException();

            Entry <K, V> e = lastReturned = nextEntry;
            nextEntry = e.after;
            return e;
        }
    }



/**
Summary: LinkedHashMap inherits HashMap. A doubly linked list is maintained internally to ensure that elements can be fetched in order or according to the least used elements.
His traversal method traverses directly from the internal doubly linked list, which is more efficient.
This class is also the best embodiment of the template design pattern. The use of several hook methods is subtle.
*/

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326447573&siteId=291194637
Recommended