【问题标题】:LinkedHashMap removeEldestEntry removing 2 elements?LinkedHashMap removeEldestEntry 删除 2 个元素?
【发布时间】:2016-05-10 04:22:33
【问题描述】:

我看了这个帖子:LinkedHashMap removeEldestEntry: How many elements are removed?

它声明 removeEldestEntry 仅删除 1 个元素。这对我来说很有意义,但是当我通过我的代码进行调试时,它似乎正在删除 2 个元素。我不知道为什么。

public class LRUCache {
    LinkedHashMap<Integer, Integer> LRUMap;

    public LRUCache(int capacity) {
        LRUMap = new LinkedHashMap<Integer, Integer>() {
            @Override
            protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
                return LRUMap.size() > capacity;
            }
        };
    }

    public int get(int key) {
        if (LRUMap.containsKey(key)) {
            int val = LRUMap.remove(key);
            LRUMap.put(key,  val);
            return val;
        }
        return -1;
    }

    public void set(int key, int value) {
        LRUMap.put(key, value);
    }

    public static void main(String[] args) {    
        LRUCache c = new LRUCache(2);
        c.set(2,1);
        c.set(1,1);
        c.set(2,3);
        c.set(4,1);
    }
}

因此您可以从中看到它将插入:(2,1)(1,1)。下一个元素是事情变得混乱的地方。因为键 2 已经存在,它用(2,3) 覆盖(2,1) 元素。在此之后,当我插入 (4,1) 时,我已经有 2 个元素,所以它应该删除最旧的条目:(1,1)。但是,它同时删除了(2,3)(1,1),在地图中只剩下(4,1)

任何想法为什么?我认为这与被替换的键和 (2,3) 位于列表的开头有关,就像它是最老的条目一样,即使它不应该是。但我仍然很困惑为什么它会删除 2 个元素。

顺便说一句,它似乎将最旧的元素存储在LinkedHashMap 的前面,这也可以让我们在恒定时间内删除最旧的条目。这是真的吗?

【问题讨论】:

  • 不,它不会删除 1,1: ideone.com/WStVFc
  • 嗯,你是对的,我的 Eclipse 现在在调试器中显示了同样的东西。也许我之前的 Eclipse 出了点问题。好的,谢谢您为我验证:)。

标签: java linkedhashmap


【解决方案1】:

要理解的LinkedHashMap 的关键行为特征是地图的Map.Entry&lt;Integer, Integer&gt; 成员被组织以保留插入顺序,它回答了与成员排序相关的问题在Map 内。因此,如果我们遍历您的 main 方法中的每一行代码,我们将看到以下内容:

  1. c.set(2,1) 之后,LRUMap 的内容将是:{2=1}
  2. c.set(1,1) 之后,LRUMap 的内容将是:{2=1, 1=1}
  3. c.set(2,3) 之后LRUMap 的内容将是:{2=3, 1=1}。此操作只是将键 (2) 映射的值从 1 更新为 3,并且被视为结构更改,因此成员的顺序得以保持。
  4. c.set(4,1) 之后,LRUMap 的内容将是:{1=1, 4=1}。映射:2=3 被认为是最旧的条目,因此将其删除(并且映射:1=1 被保留)。

由于您的意图很明确,您想要创建 最近最少使用 缓存,您应该考虑更改 LinkedHashMap 的构造以远离 插入- order 成员存储有利于 last-access 成员排序。 LinkedHashMap 类提供了一个替代构造函数来支持这种用法:

public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)

如果您为accessOrder 参数传递值:true,则成员映射将存储在 access-order 中(这是您要用于 LRU 缓存的)或如果您为accessOrder 参数传递值:false,则成员映射将存储在插入顺序中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 2018-03-23
    相关资源
    最近更新 更多