LinkedHashMap原理分析

LinkedHashMap原理分析

一.实现


LinkedHashMap继承HashMap
数据结构:HashMapEntry(key,value)--》LinkedHashMapEntry(key,value+before指针和after指针(双向链表))
1.构造函数LinkedHashMap
/*
    accessOrder true if the ordering should be done based on the last access (from least-recently accessed to most-recently     accessed), and false if the ordering should be the order in which the entries were inserted.
*/
public LinkedHashMap(
        int initialCapacity, float loadFactor, boolean accessOrder) {
    super(initialCapacity, loadFactor);
    init();
    this.accessOrder = accessOrder;
}

super(initialCapacity, loadFactor) {
    // 新建一个HashMap-->创建HashMap对应的集合
    ...
}

@Override 
void init() {
    header = new LinkedEntry<K, V>();
}

/*
    LinkedEntry是双向链表+HashMap的item
    LinkedEntry是HashMapEntry的子类
    HashMapEntry是HashMap的item
*/
static class LinkedEntry<K, V> extends HashMapEntry<K, V> {

    LinkedEntry<K, V> nxt;
    LinkedEntry<K, V> prv;

    /** Create the header entry */
    LinkedEntry() {
        super(null, null, 0, null);
        nxt = prv = this;
    }

    /** Create a normal entry */
    LinkedEntry(K key, V value, int hash, HashMapEntry<K, V> next,
        LinkedEntry<K, V> nxt, LinkedEntry<K, V> prv) {
        super(key, value, hash, next);// 调用HashMap的构造函数
        this.nxt = nxt;
        this.prv = prv;
    }
}

2.put函数--同HashMap的put函数
// 覆写该函数
// 修改已经put进去的key对应的value的时候会调用该函数
@Override 
void preModify(HashMapEntry<K, V> e) {
    if (accessOrder) {
        makeTail((LinkedEntry<K, V>) e);
    }
}

// 将e元素插入到循环双向链表的末尾(如果之前已经插入到循环双向链表中,则删除,然后插入到末尾)
/**
* Relinks the given entry to the tail of the list. Under access ordering,
* this method is invoked whenever the value of a  pre-existing entry is
* read by Map.get or modified by Map.put.
*/
private void makeTail(LinkedEntry<K, V> e) {// Tail:尾巴
    // Unlink e
    e.prv.nxt = e.nxt;
    e.nxt.prv = e.prv;

    // header是LinkedEntry的链表,LinkedEntry在1构造函数中有介绍
    // Relink e as tail
    LinkedEntry<K, V> header = this.header;
    // 将e插入到循环双向链表的最后一个元素
    LinkedEntry<K, V> oldTail = header.prv;
    e.nxt = header;
    e.prv = oldTail;
    oldTail.nxt = header.prv = e;
    modCount++;
}

// 覆写该函数--相当于调用makeTail,把item插入到双向队列的末尾
@Override 
void addNewEntry(K key, V value, int hash, int index) {
    LinkedEntry<K, V> header = this.header;

    // Remove eldest entry if instructed to do so.
    LinkedEntry<K, V> eldest = header.nxt;
    if (eldest != header && removeEldestEntry(eldest)) {
        remove(eldest.key);
    }

    // Create new entry, link it on to list, and put it into table
    LinkedEntry<K, V> oldTail = header.prv;
    LinkedEntry<K, V> newTail = new LinkedEntry<K,V>(key, value, hash, table[index], header, oldTail);
    table[index] = oldTail.nxt = header.prv = newTail;
}

3.get函数
// 该实现和HashMap的get函数实现几乎一样,除了注释的那句代码外
@Override 
public V get(Object key) {
    ...

    // Replace with Collections.secondaryHash when the VM is fast enough (http://b/8290590).
    int hash = secondaryHash(key);
    HashMapEntry<K, V>[] tab = table; // HashMap.java的table
    for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
            e != null; e = e.next) {
        K eKey = e.key;
        if (eKey == key || (e.hash == hash && key.equals(eKey))) {
            if (accessOrder) // 添加的代码.如果是按照Lru算法实现,这重新调整该item在循环双向链表中的位置
                makeTail((LinkedEntry<K, V>) e);
            return e.value;
        }
    }
    return null;
}

4.remove函数--同HashMap的remove函数
// 覆写通知函数
// 将该item从双向循环链表中删除
@Override 
void postRemove(HashMapEntry<K, V> e) {
    LinkedEntry<K, V> le = (LinkedEntry<K, V>) e;
    le.prv.nxt = le.nxt;
    le.nxt.prv = le.prv;
    le.nxt = le.prv = null; // Help the GC (for performance)
}

二.总结

1.要了解LinedHashMap的实现,要先知道他的父类HashMap的实现,LinkedHashMap的大部分实现都在他父类中实现
2.当开启Lru算法的时候(accessOrder参数设置为true),LinkedHashMap比HashMap多的是该类自己维护双向循环链表,当增删改的时候会修改该链表,把最新的item放到末尾(Tail)
3.本质:LinkedHashMap == HashMap + LinkedList
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值