LinkedHashMap 是如何实现的
LinkedHash 底层基于 HashMap 实现并扩展了 HashMap.Node 使其支持双向链表
LinkedHashMap 两种有序
1. 插入有序
示例代码:
HashMap<String, Integer> hashMap = new HashMap<>();
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
for (int i = 0; i < 10; i++) {
hashMap.put("index-" + i, i);
linkedHashMap.put("index-" + i, i);
}
System.out.println(hashMap);
System.out.println(linkedHashMap);
输出:
{index-0=0, index-1=1, index-2=2, index-7=7, index-8=8, index-9=9, index-3=3, index-4=4, index-5=5, index-6=6}
{index-0=0, index-1=1, index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-8=8, index-9=9}
可以注意到 HashMap 由于 Hash 算法的特性,遍历输出并不是顺序。 LinkedHashMap虽然实现基于 hashMap 由于内部维护了双向链表所以支持按照插入顺序进行输出。
2.访问有序 (当 accessOrder = true)
示例代码:
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 4, 8, 2, 55, 3, 4, 8, 6, 4, 0, 11, 34, 90, 23, 54, 77, 9, 2, 9, 4, 10);
System.out.println(slow(numbers));
HashMap<String, Integer> hashMap = new HashMap<>();
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>(10, 1, true);
for (int i = 0; i < 10; i++) {
hashMap.put("index-" + i, i);
linkedHashMap.put("index-" + i, i);
}
for (int i = 5; i >= 0; i--) {
linkedHashMap.get("index-" + i);
}
System.out.println(hashMap);
System.out.println(linkedHashMap);
}
输出:
{index-0=0, index-1=1, index-2=2, index-7=7, index-8=8, index-9=9, index-3=3, index-4=4, index-5=5, index-6=6}
{index-6=6, index-7=7, index-8=8, index-9=9, index-5=5, index-4=4, index-3=3, index-2=2, index-1=1, index-0=0}
当某个元素被访问后将此元素移动在链表尾部,基于此特性我们可以实现 LRU (Least Recently Used) 即在内存缓存或分布式缓存中常见的清理策略。
基于 LinkedHashMap 实现 LRU
基于 LinkedHashMap 实现 LRU 共有如下几步
- 继承 LinkedHashMap 或包装LinedHashMap
- 设定 LinkedHashMap 按照访问排序
- 确定 LRU 容器最大容量
- 重写 removeEldestEntry 方法保证容器长度固定
示例代码:
public class LRU<K,V> extends LinkedHashMap<K, V> implements Map<K, V> {
private final int maxSize;
public LRU(int initialCapacity, float loadFactor, int maxSize) {
super(initialCapacity, loadFactor, true);
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Entry<K, V> eldest) {
return size() > maxSize;
}
public static void main(String[] args) {
LRU<String, Integer> lru = new LRU<>(10, 1, 10);
for (int i = 0 ; i < 10; i++){
lru.put("index-" + i,i);
}
System.out.println(lru);
lru.get("index-9");
lru.get("index-8");
lru.get("index-0");
System.out.println(lru);
lru.put("index-11", 11);
System.out.println(lru);
}
}
输出内容:
{index-0=0, index-1=1, index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-8=8, index-9=9}
{index-1=1, index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-9=9, index-8=8, index-0=0}
{index-2=2, index-3=3, index-4=4, index-5=5, index-6=6, index-7=7, index-9=9, index-8=8, index-0=0, index-11=11}
通过输出可以看到根据 LRU 思想移除掉了 index-1,基于 LinkedHashMap 的 LRU 容器始终保持最大容量 10
浙公网安备 33010602011771号