源码的核心是数据结构
最近在读缓存图片框架的源码,一直不知道缓存是如何判断“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的末尾,实现了访问排序,如果大家有不懂得可以在评论留言哈,我也是在研究中,欢迎一起学习一起进步~