LinkHashMap

HashMap是无序的:利用迭代器访问HashMap的顺序和其插入的顺序是不一致的。当需要有序访问时,可以使用LinkHashMap。

LinkedHashMap可以认为是HashMap+LinkedList,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序。

结构图:

LinkHashMap的Entry继承了HashMap的Entry,增加了两个指针,用于维护一个Entry的双向链表;双向列表的头指针为header。

private static class Entry<K,V> extends HashMap.Entry<K,V> {
    //增加了before,after两个指针,维护Entry顺序
    Entry<K,V> before, after;

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

    //删除该Entry
    private void remove() {
        before.after = after;
        after.before = before;
    }

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

    //在HashMap中调用,可以实现LRU算法
    void recordAccess(HashMap<K,V> m) {
        LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
        if (lm.accessOrder) {
            lm.modCount++;
            remove();
            addBefore(lm.header);
        }
    }

    void recordRemoval(HashMap<K,V> m) {
        remove();
    }
}

LinkedHashMap继承了HashMap

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{

    //双向链表的头指针
    private transient Entry<K,V> header;

    //链表的顺序;false:插入顺序,true:访问顺序
    private final boolean accessOrder;
}

LinkedHashMap并未重写父类HashMap的put方法,而是重写了父类HashMap的put方法调用的子方法void addEntry(int hash, K key, V value, int bucketIndex) 和void createEntry(int hash, K key, V value, int bucketIndex),提供了自己特有的双向链接列表的实现。

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;  
    // 调用Entry的addBrefore方法,将元素加入到双向链表中
    e.addBefore(header);  
    size++;  
}  

get方法读取元素

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);  
    }  
}  

 

posted @ 2018-05-05 13:46  saiQsai  阅读(399)  评论(0编辑  收藏  举报