Java之LinkedHashMap

LinkedHashMap

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

一、关于LinkedHashMap

LinkedHashMap继承自HashMap,具有和HashMap一样的快速查找特性。

对比与HashMap,LinkedHashMap内部维护了一个双向链表,用来维护插入顺序或者LRU顺序。迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序的。LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。

 

二、LinkedHashMap存储结构

1.LinkedHashMap可以认为是HashMap+LinkeList,既使用HashMap来操作数据结构,又使用LinkedList来维护插入或访问元素的先后次序。

2.内部的双向链表

/**
 * The head (eldest) of the doubly linked list.
 */
transient LinkedHashMap.Entry<K,V> head;

/**
 * The tail (youngest) of the doubly linked list.
 */
transient LinkedHashMap.Entry<K,V> tail;

accessOrder决定了顺序,默认为false,维护的是插入顺序。当accessOrder为true时,则维护的是最近最少使用次序。也就是当accessOrder为true时,当一个节点被访问时,会将该节点移到链表的尾部,插入一个节点也是从尾部插入

final boolean accessOrder;

afterNodeAccess()

// 当accessOrder为true时,在访问节点之后,将其移到链表的尾部
void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMap.Entry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
            }
            tail = p;
            ++modCount;
        }
    }

3. LinkedHashMap结构图

这里要注意区分next和before、After,next是用于维护HashMap指定table位置上连接的Entry的顺序的,before、After是用于维护Entry插入的先后顺序的。同时,next也是原HashMap中已有的。

根据LinkeList维护顺序的特点,在该链表中,循环双向链表的头部存放的是最久访问的节点或最先插入的节点尾部为最近访问的或最近插入的节点,迭代器遍历方向是从链表的头部开始到链表尾部结束,在链表尾部有一个空的header节点,该节点不存放key-value内容,为LinkedHashMap类的成员属性,循环双向链表的入口。

afterNodeInsertion

在put等操作之后执行,当removeEldestEntry()方法返回true时会移动最晚的节点,也就是链表首部节点first

void afterNodeRemoval(Node<K,V> e) { // unlink
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        p.before = p.after = null;
        if (b == null)
            head = a;
        else
            b.after = a;
        if (a == null)
            tail = b;
        else
            a.before = b;
    }

 

HashMap结构图:

三、利用LinkedHashMap实现LRU算法缓存

LRU是Least Recently Used的缩写,即最近最少使用。

LinkedHashMap可以实现LRU算法的缓存基于两点:

    1、LinkedList首先它是一个Map,Map是基于K-V的,和缓存一致

    2、LinkedList提供了一个boolean值可以让用户指定是否实现LRU

使用LinkedListHashMap实现一个LRU缓存:

  设置最大缓存空间MAX_ENTRIES为3

  使用LinkedListHashMap构造函数将accessOrder设置为true,开启LRU顺序。

  覆盖remove1,EldestEntry()方法实现,在节点多于MAX_ENTRIES将最近最久未使用的数据移除

class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private static final int MAX_ENTRIES = 3;

    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_ENTRIES;
    }

    LRUCache() {
        super(MAX_ENTRIES, 0.75f, true);
    }
}
public static void main(String[] args) {
    LRUCache<Integer, String> cache = new LRUCache<>();
    cache.put(1, "a");
    cache.put(2, "b");
    cache.put(3, "c");
    cache.get(1);
    cache.put(4, "d");
    System.out.println(cache.keySet());
}

输出结果:[3, 1, 4]

参考博客:

https://www.cnblogs.com/xiaoxi/p/6170590.html

https://cyc2018.github.io/CS-Notes

https://www.cnblogs.com/chengxiao/p/6059914.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值