LinkedHashMap的基本用法&简单的LRU缓存


LinkedHashMap是HashMap的子类,但可以保持元素 按插入或访问有序,这与TreeMap按键排序不同

基本用法

LinkedHashMap是HashMap的子类,但内部还有一个双向链表维护键值对的顺序,每个键值对既位于哈希表中,也位于这个双向链表中。
LinkedHashMap支持两种顺序:一种是插入顺序;还有一种是访问顺序。
插入顺序:先添加的在前面,后添加的在后面,修改操作不影响顺序;
访问顺序:对一个键进行get/put操作后,其对应的键值对会移到链表末尾,所以末尾的是最近访问的,最开始的最久没被访问。

LinkedHashMap有5个构造方法,其中4个都是按插入排序,只有一个构造方法可以指定按访问顺序:

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

accessOrder参数用来指定是否按照访问排序,如果true,就是按照访问书序。
默认情况下,LinkedHashMap是按照插入有序的:

        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("a", "a");
        linkedHashMap.put("b", "b");
        linkedHashMap.put("c", "c");
        linkedHashMap.put("b", "bbbb");
        for (Map.Entry<String, String> entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }

输出为:

a:a
b:bbbb
c:c

修改b的值不会修改顺序

访问有序的例子:

        LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>(16,0.75f,true);
        linkedHashMap.put("a", "a");
        linkedHashMap.put("b", "b");
        linkedHashMap.put("c", "c");
        linkedHashMap.put("b", "bbbb");
        for (Map.Entry<String, String> entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }

每次访问,都将键值对移动到末尾,输出为:

a:a
c:c
b:bbbb

什么时候希望按照访问有序呢?一种典型的应用就是LRU缓存
ps:缓存容量有限,不能无限存储所有数据,如果缓存满了,就需要一定的策略将老的数据清除,这一策略称为替换算法。
LRU是一种流行的替换算法,它的全称是Least Recently Used,即最近最少使用。它认为最近刚被使用过的很快再次被用的可能性最高,而最久没有被访问的很快再次被访问的可能性最低,所以优先被清理。

虽然LinkedHashMap没有对容量做限制,但它可以轻易做到,它有一个protected方法:

    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

在元素添加到LinkedHashMap后,LinkedHashMap会调用这个方法,传递的参数是最久没有被访问的键值对,如果这个方法返回true,则这个最久的键值对就会被删除。LinkedHashMap的实现总是返回false,所以容量没有限制,但子类可以重写该方法,在满足一定的条件下返回true;

使用LinkedHashMap实现一个简单的LRU实现:

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private int maxEntries;

    public LRUCache(int maxEntries) {
        super(16, 0.75f, true);
        this.maxEntries = maxEntries;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > maxEntries;
    }
}

使用这个缓存:

        LRUCache<String, String> cache = new LRUCache<>(3);
        cache.put("a", "a");
        cache.put("b", "b");
        cache.put("c", "c");
        cache.put("a", "aaa");
        cache.put("d", "d");
        System.out.println(cache);

输出为:

{c=c, a=aaa, d=d}

ps:添加d的时候,最久没被访问的b会被删除

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值