LinkedHashMap是如何实现访问排序的?

源码的核心是数据结构

最近在读缓存图片框架的源码,一直不知道缓存是如何判断“LRU” (Least Recently Used)最近最少使用的,看了源码才知道核心是LRUCache类,这个类的核心其实是 LinkedHashMap类

关于这个类的介绍,网上有很多资料介绍这个类的特性:

1 双向链表+哈希表

2 线程不安全

3 允许空的键或者值

4 有序

有一篇博客很详细介绍了这个类

如果想要了解更多,请看这里~

以上只是搬运知识罢了,接下来讲讲大家最关心的问题:

LinkedHashMap是如何实现访问排序的?

首先讲下什么是访问排序? 什么是插入排序?

插入排序就是你put的时候的顺序是什么,取出来的时候就是什么样子

 LinkedHashMap<String, String> map = new LinkedHashMap<>(10,0.75f,false);

        for(int i=0; i<10; i++) {
            map.put("key" + i, i+"");
        }
        
        String s = map.get("key2");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }

结果如下所示(如果两个key一样的话,会覆盖点前面的值但是顺序不变

Key = key0, Value = 0
Key = key1, Value = 1
Key = key2, Value = 2
Key = key3, Value = 3
Key = key4, Value = 4
Key = key5, Value = 5
Key = key6, Value = 6
Key = key7, Value = 7
Key = key8, Value = 8
Key = key9, Value = 9

访问排序就是你get的时候,会改变元素的顺序,会把该元素移到数据的末尾

 LinkedHashMap<String, String> map = new LinkedHashMap<>(10,0.75f,true);

        for(int i=0; i<10; i++) {
            map.put("key" + i, i+"");
        }

        String s = map.get("key2");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }

结果如下:

Key = key0, Value = 0
Key = key1, Value = 1
Key = key3, Value = 3
Key = key4, Value = 4
Key = key5, Value = 5
Key = key6, Value = 6
Key = key7, Value = 7
Key = key8, Value = 8
Key = key9, Value = 9
Key = key2, Value = 2

我们可以看到key2变成了数据的最后一个元素

1 如何设置按照访问排序或者按照插入排序?

访问排序

 LinkedHashMap<String, String> map = new LinkedHashMap<>(10,0.75f,true);

插入排序

 LinkedHashMap<String, String> map = new LinkedHashMap<>(10,0.75f,false);

2 访问排序是如何实现的?

 public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }
   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;
        }
    }

关于链表我其实也是很晕的,只能勉强看懂代码但是自己写肯定还是生疏

这里写图片描述

上图是我按照源码的逻辑画出来的,e1,e,e2表示的是原来的map顺序,经过层层判断和更改引用之后,p已经独立出来了,这个时候执行

p.before = last;
last.after = p;

就把p移到了map的末尾,实现了访问排序,如果大家有不懂得可以在评论留言哈,我也是在研究中,欢迎一起学习一起进步~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值