LinkedHashMap 源码分析学习

LinkedHashMap 是一个有序集合,默认是按插入顺序进行排序,也支持按照最近访问的数据在最后面(accessOrder=true)

LinkedHashMap 继承了 HashMap ,在Entry中继承了HashMap的Node 内部类,并新增加before 和 after,使得有序。

LinkedHashMap 并没有实现 HashMap 的put方法,而是在putVal 方法中,执行newNode 时,重写了newNode方法。

主要代码

// 继承了HashMap.Node 内部类,并新增了before 和 after 节点
static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}
// 按照存储的顺序
public LinkedHashMap() {
    super();
    accessOrder = false;
}
// accessOrder 如果是true ,则将最新访问的元素放到最后面。
public LinkedHashMap(int initialCapacity,
                     float loadFactor,
                     boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        // ......
        if ((p = tab[i = (n - 1) & hash]) == null)
            // 当是LinkedHashMap时 ,执行LinkedHashMap重写的方法
            tab[i] = newNode(hash, key, value, null);
    else {
        // ......
    }
    // ......
    // HashMap 没有实现
    // 对LinkedHashMap 有用,用来回调移除最早放入Map的对象
    afterNodeInsertion(evict);
    return null;
}
// LinkedHashMap 使用的是HashMap的模板方法,
// 只是此处的数组节点是继承了HashMap.Entry ,进行增加了before 和after ,从而实现有序
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    LinkedHashMap.Entry<K,V> p =
        new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    linkNodeLast(p);
    return p;
}
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    LinkedHashMap.Entry<K,V> last = tail;
    tail = p;
    if (last == null)
        head = p;
    else {
        p.before = last;
        last.after = p;
    }
}
// LinkedHashMap中被覆盖的afterNodeInsertion方法,用来回调移除最早放入Map的对象
void afterNodeInsertion(boolean evict) { // possibly remove eldest
    LinkedHashMap.Entry<K,V> first;
    if (evict && (first = head) != null && removeEldestEntry(first)) {
        K key = first.key;
        removeNode(hash(key), key, null, false, true);
    }
}

基于 LinkedHashMap 实现 LRU 淘汰策略

package com.guaoran.interview.in2018.collection.map;

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

/**
 * @Author gucheng
 * @Description
 *    重写 {@link LinkedHashMap#removeEldestEntry(Map.Entry)} 来实现 LRU 淘汰策略
 * 2019-03-18 9:30
 */
public class LinkedHashMapLRU<K,V> extends LinkedHashMap<K,V> {
    private int initialCapacity;

    public LinkedHashMapLRU(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
        this.initialCapacity  = initialCapacity;
    }
    

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        if(size() > this.initialCapacity){
            System.out.println(eldest + "删除了");
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Map<String,Integer> sortMapLRU = new LinkedHashMapLRU<String,Integer>(16,0.75f);
        for (int i = 0; i < 10; i++) {
            sortMapLRU.put("key"+i,i);
        }
        sortMapLRU.entrySet().forEach(m ->{
            System.out.println(m.getKey()+" -> "+m.getValue());
        });
        System.out.println(sortMapLRU.get("key9"));
        System.out.println(sortMapLRU.get("key5"));
        System.out.println(sortMapLRU.get("key3"));

        sortMapLRU.entrySet().forEach(m ->{
            System.out.println(m.getKey()+" -> "+m.getValue());
        });

        System.out.println("LRU.....................start");
        for (int i = 10; i < 20; i++) {
            sortMapLRU.put("key"+i,i);
        }

        sortMapLRU.entrySet().forEach(m ->{
            System.out.println(m.getKey()+" -> "+m.getValue());
        });
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值