LinkedHashMap解读

本文详细解析了LinkedHashMap的数据结构和工作原理,包括其继承自HashMap的特点、双向链表的实现、插入顺序与访问顺序的区别,以及如何利用removeEldestEntry方法实现LRU缓存。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


 

HashMap:

        put -> addEntry(新建一个Entry)

        get

        getEntry

 

LinkedHashMap:

       put -> addEntry(重写)

                新建一个Entry,然后将其加入header前

                e.addBefore(header)

 

       get -> 调用HashMap的getEntry - recordAccess(重写)

 

HashMap的get与getEntry

 

Java代码   收藏代码
  1. final Entry<K,V> getEntry(Object key) {  
  2.         int hash = (key == null) ? 0 : hash(key.hashCode());  
  3.         for (Entry<K,V> e = table[indexFor(hash, table.length)];  
  4.              e != null;  
  5.              e = e.next) {  
  6.             Object k;  
  7.             if (e.hash == hash &&  
  8.                 ((k = e.key) == key || (key != null && key.equals(k))))  
  9.                 return e;  
  10.         }  
  11.         return null;  
  12.     }  
  13.       
  14.       
  15.     public V get(Object key) {  
  16.         if (key == null)  
  17.             return getForNullKey();  
  18.         int hash = hash(key.hashCode());  
  19.         for (Entry<K,V> e = table[indexFor(hash, table.length)];  
  20.              e != null;  
  21.              e = e.next) {  
  22.             Object k;  
  23.             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))  
  24.                 return e.value;  
  25.         }  
  26.         return null;  
  27.     }  

 

 

1. LinkedHashMap概述:

LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap。

   LinkedHashMap是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变
   LinkedHashMap实现与HashMap的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。
   注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。

 

根据链表中元素的顺序可以分为:按插入顺序的链表,和按访问顺序(调用get方法)的链表。  

默认是按插入顺序排序,如果指定按访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。  可以重写removeEldestEntry方法返回true值指定插入元素时移除最老的元素。 

 

2. LinkedHashMap的实现:

   对于LinkedHashMap而言,它继承与HashMap、底层使用哈希表与双向链表来保存所有元素。其基本操作与父类HashMap相似,它通过重写父类相关的方法,来实现自己的链接列表特性。下面我们来分析LinkedHashMap的源代码:

类结构:

Java代码   收藏代码
  1. public class LinkedHashMap<K, V> extends HashMap<K, V> implements Map<K, V>    

 

 1) 成员变量:

   LinkedHashMap采用的hash算法和HashMap相同,但是它重新定义了数组中保存的元素Entry,该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而在哈希表的基础上又构成了双向链接列表。看源代码:

 

Java代码   收藏代码
  1. //true表示按照访问顺序迭代,false时表示按照插入顺序  
  2.  private final boolean accessOrder;  
  1. /** 
  2.  * 双向链表的表头元素。 
  3.  */  
  4. private transient Entry<K,V> header;  
  5.   
  6. /** 
  7.  * LinkedHashMap的Entry元素。 
  8.  * 继承HashMap的Entry元素,又保存了其上一个元素before和下一个元素after的引用。 
  9.  */  
  10. private static class Entry<K,V> extends HashMap.Entry<K,V> {  
  11.     Entry<K,V> before, after;  
  12.     ……  
  13. }  

HashMap.Entry:

Java代码   收藏代码
  1. static class Entry<K,V> implements Map.Entry<K,V> {  
  2.         final K key;  
  3.         V value;  
  4.         Entry<K,V> next;  
  5.         final int hash;  
  6.   
  7.         Entry(int h, K k, V v, Entry<K,V> n) {  
  8.             value = v;  
  9.             next = n;  
  10.             key = k;  
  11.             hash = h;  
  12.         }  
  13. }  

  

    2) 初始化:

   通过源代码可以看出,在LinkedHashMap的构造方法中,实际调用了父类HashMap的相关构造方法来构造一个底层存放的table数组。如:

Java代码 
  1. public LinkedHashMap(int initialCapacity, float loadFactor) {  
  2.     super(initialCapacity, loadFactor);  
  3.     accessOrder = false;  
  4. }  

    HashMap中的相关构造方法:

Java代码 
  1. public HashMap(int initialCapacity, float loadFactor) {  
  2.     if (initialCapacity < 0)  
  3.         throw new IllegalArgumentException("Illegal initial capacity: " +  
  4.                                            initialCapacity);  
  5.     if (initialCapacity > MAXIMUM_CAPACITY)  
  6.         initialCapacity = MAXIMUM_CAPACITY;  
  7.     if (loadFactor <= 0 || Float.isNaN(loadFactor))  
  8.         throw new IllegalArgumentException("Illegal load factor: " +  
  9.                                            loadFactor);  
  10.   
  11.     // Find a power of 2 >= initialCapacity  
  12.     int capacity = 1;  
  13.     while (capacity < initialCapacity)  
  14.         capacity <<= 1;  
  15.   
  16.     this.loadFactor = loadFactor;  
  17.     threshold = (int)(capacity * loadFactor);  
  18.     table = new Entry[capacity];  
  19.     init();  
  20. }  

    我们已经知道LinkedHashMap的Entry元素继承HashMap的Entry,提供了双向链表的功能。在上述HashMap的构造器中,最后会调用init()方法,进行相关的初始化,这个方法在HashMap的实现中并无意义,只是提供给子类实现相关的初始化调用。
   LinkedHashMap重写了init()方法,在调用父类的构造方法完成构造后,进一步实现了对其元素Entry的初始化操作。

Java代码 
  1. void init() {  
  2.     header = new Entry<K,V>(-1nullnullnull);  
  3.     header.before = header.after = header;  
  4. }  

    3) 存储:

   LinkedHashMap并未重写父类HashMap的put方法,而是重写了父类HashMap的put方法调用的子方法void recordAccess(HashMap m)  ,void addEntry(int hash, K key, V value, int bucketIndex) 和void createEntry(int hash, K key, V value, int bucketIndex),提供了自己特有的双向链接列表的实现。

HashMap.put:

 

Java代码   收藏代码
  1. public V put(K key, V value) {  
  2.         if (key == null)  
  3.             return putForNullKey(value);  
  4.         int hash = hash(key.hashCode());  
  5.         int i = indexFor(hash, table.length);  
  6.         for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
  7.             Object k;  
  8.             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
  9.                 V oldValue = e.value;  
  10.                 e.value = value;  
  11.                 e.recordAccess(this);  
  12.                 return oldValue;  
  13.             }  
  14.         }  
  15.   
  16.         modCount++;  
  17.         addEntry(hash, key, value, i);  
  18.         return null;  
  19.     }  

 重写方法:

Java代码   收藏代码
  1. void recordAccess(HashMap<K,V> m) {  
  2.             LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;  
  3.             if (lm.accessOrder) {  
  4.                 lm.modCount++;  
  5.                 remove();  
  6.                 addBefore(lm.header);  
  7.             }  
  8.         }  

 

 
  1. void addEntry(int hash, K key, V value, int bucketIndex) {  
  2.     // 调用create方法,将新元素以双向链表的的形式加入到映射中。  
  3.     createEntry(hash, key, value, bucketIndex);  
  4.   
  5.     // 删除最近最少使用元素的策略定义  
  6.     Entry<K,V> eldest = header.after;  
  7.     if (removeEldestEntry(eldest)) {  
  8.         removeEntryForKey(eldest.key);  
  9.     } else {  
  10.         if (size >= threshold)  
  11.             resize(2 * table.length);  
  12.     }  
  13. }  
Java代码 
  1. void createEntry(int hash, K key, V value, int bucketIndex) {  
  2.     HashMap.Entry<K,V> old = table[bucketIndex];  
  3.     Entry<K,V> e = new Entry<K,V>(hash, key, value, old);  
  4.     table[bucketIndex] = e;  
  5.     // 调用元素的addBrefore方法,将元素加入到哈希、双向链接列表。  
  6.     e.addBefore(header);  
  7.     size++;  
  8. }  
Java代码 
  1. private void addBefore(Entry<K,V> existingEntry) {  
  2.     after  = existingEntry;  
  3.     before = existingEntry.before;  
  4.     before.after = this;  
  5.     after.before = this;  
  6. }  

   

4) 读取:

   LinkedHashMap重写了父类HashMap的get方法,实际在调用父类getEntry()方法取得查找的元素后,再判断当排序模式accessOrder为true时,记录访问顺序,将最新访问的元素添加到双向链表的表头,并从原来的位置删除。由于的链表的增加、删除操作是常量级的,故并不会带来性能的损失。

HashMap.containsValue:

Java代码   收藏代码
  1. public boolean containsValue(Object value) {  
  2.     if (value == null)  
  3.             return containsNullValue();  
  4.   
  5.     Entry[] tab = table;  
  6.         for (int i = 0; i < tab.length ; i++)  
  7.             for (Entry e = tab[i] ; e != null ; e = e.next)  
  8.                 if (value.equals(e.value))  
  9.                     return true;  
  10.     return false;  
  11.     }  

 

Java代码   收藏代码
  1.  /*查找Map中是否包含给定的value,还是考虑到,LinkedHashMap拥有的双链表,在这里Override是为了提高迭代的效率。 
  2.  */  
  3. public boolean containsValue(Object value) {  
  4.         // Overridden to take advantage of faster iterator  
  5.         if (value==null) {  
  6.             for (Entry e = header.after; e != header; e = e.after)  
  7.                 if (e.value==null)  
  8.                     return true;  
  9.         } else {  
  10.             for (Entry e = header.after; e != header; e = e.after)  
  11.                 if (value.equals(e.value))  
  12.                     return true;  
  13.         }  
  14.         return false;  
  15.     }  

 

 

Java代码   收藏代码
  1. /*该transfer()是HashMap中的实现:遍历整个表的各个桶位,然后对桶进行遍历得到每一个Entry,重新hash到newTable中, 
  2.  //放在这里是为了和下面LinkedHashMap重写该法的比较, 
  3.  void transfer(Entry[] newTable) { 
  4.         Entry[] src = table; 
  5.         int newCapacity = newTable.length; 
  6.         for (int j = 0; j < src.length; j++) { 
  7.             Entry<K,V> e = src[j]; 
  8.             if (e != null) { 
  9.                 src[j] = null; 
  10.                 do { 
  11.                     Entry<K,V> next = e.next; 
  12.                     int i = indexFor(e.hash, newCapacity); 
  13.                     e.next = newTable[i]; 
  14.                     newTable[i] = e; 
  15.                     e = next; 
  16.                 } while (e != null); 
  17.             } 
  18.         } 
  19.     } 
  20.  */  
  21.   
  22.  /** 
  23.  *transfer()方法是其父类HashMap调用resize()的时候调用的方法,它的作用是表扩容后,把旧表中的key重新hash到新的表中。 
  24.  *这里从写了父类HashMap中的该方法,是因为考虑到,LinkedHashMap拥有的双链表,在这里Override是为了提高迭代的效率。 
  25.  */  
  26.  void transfer(HashMap.Entry[] newTable) {  
  27.    int newCapacity = newTable.length;  
  28.    for (Entry<K, V> e = header.after; e != header; e = e.after) {  
  29.      int index = indexFor(e.hash, newCapacity);  
  30.      e.next = newTable[index];  
  31.      newTable[index] = e;  
  32.    }  
  33.  }  

 

Java代码 
  1. public V get(Object key) {  
  2.     // 调用父类HashMap的getEntry()方法,取得要查找的元素。  
  3.     Entry<K,V> e = (Entry<K,V>)getEntry(key);  
  4.     if (e == null)  
  5.         return null;  
  6.     // 记录访问顺序。  
  7.     e.recordAccess(this);  
  8.     return e.value;  
  9. }  
Java代码 
  1. void recordAccess(HashMap<K,V> m) {  
  2.     LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;  
  3.     // 如果定义了LinkedHashMap的迭代顺序为访问顺序,  
  4.     // 则删除以前位置上的元素,并将最新访问的元素添加到链表表头。  
  5.     if (lm.accessOrder) {  
  6.         lm.modCount++;  
  7.         remove();  
  8.         addBefore(lm.header);  
  9.     }  
  10. }  

 

Java代码   收藏代码
  1. /** 
  2.          * Removes this entry from the linked list. 
  3.          */  
  4.         private void remove() {  
  5.             before.after = after;  
  6.             after.before = before;  
  7.         }  

 

 

Java代码   收藏代码
  1. /**clear链表,设置header为初始状态*/  
  2. public void clear() {  
  3.  super.clear();  
  4.  header.before = header.after = header;  
  5. }  

 

 

    5) 排序模式:

   LinkedHashMap定义了排序模式accessOrder,该属性为boolean型变量,对于访问顺序,为true;对于插入顺序,则为false。

Java代码 
  1. private final boolean accessOrder;  

 一般情况下,不必指定排序模式,其迭代顺序即为默认为插入顺序。看LinkedHashMap的构造方法,如:

Java代码 
  1. public LinkedHashMap(int initialCapacity, float loadFactor) {  
  2.     super(initialCapacity, loadFactor);  
  3.     accessOrder = false;  
  4. }  

    这些构造方法都会默认指定排序模式为插入顺序。如果你想构造一个LinkedHashMap,并打算按从近期访问最少到近期访问最多的顺序(即访问顺序)来保存元素,那么请使用下面的构造方法构造LinkedHashMap:

Java代码 
  1. public LinkedHashMap(int initialCapacity,  
  2.          float loadFactor,  
  3.                      boolean accessOrder) {  
  4.     super(initialCapacity, loadFactor);  
  5.     this.accessOrder = accessOrder;  
  6. }  

    该哈希映射的迭代顺序就是最后访问其条目的顺序,这种映射很适合构建LRU缓存。LinkedHashMap提供了removeEldestEntry(Map.Entry<K,V> eldest)方法。该方法可以提供在每次添加新条目时移除最旧条目的实现程序,默认返回false,这样,此映射的行为将类似于正常映射,即永远不能移除最旧的元素。

 

当有新元素加入Map的时候会调用Entry的addEntry方法,会调用removeEldestEntry方法,这里就是实现LRU元素过期机制的地方,默认的情况下removeEldestEntry方法只返回false表示元素永远不过期。

Java代码    收藏代码
  1.   /** 
  2.     * This override alters behavior of superclass put method. It causes newly 
  3.     * allocated entry to get inserted at the end of the linked list and 
  4.     * removes the eldest entry if appropriate. 
  5.     */  
  6.    void addEntry(int hash, K key, V value, int bucketIndex) {  
  7.        createEntry(hash, key, value, bucketIndex);  
  8.   
  9.        // Remove eldest entry if instructed, else grow capacity if appropriate  
  10.        Entry<K,V> eldest = header.after;  
  11.        if (removeEldestEntry(eldest)) {  
  12.            removeEntryForKey(eldest.key);  
  13.        } else {  
  14.            if (size >= threshold)   
  15.                resize(2 * table.length);  
  16.        }  
  17.    }  
  18.   
  19.    /** 
  20.     * This override differs from addEntry in that it doesn't resize the 
  21.     * table or remove the eldest entry. 
  22.     */  
  23.    void createEntry(int hash, K key, V value, int bucketIndex) {  
  24.        HashMap.Entry<K,V> old = table[bucketIndex];  
  25. Entry<K,V> e = new Entry<K,V>(hash, key, value, old);  
  26.        table[bucketIndex] = e;  
  27.        e.addBefore(header);  
  28.        size++;  
  29.    }  
  30.   
  31.    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {  
  32.        return false;  
  33.    }  

此方法通常不以任何方式修改映射,相反允许映射在其返回值的指引下进行自我修改。如果用此映射构建LRU缓存,则非常方便,它允许映射通过删除旧条目来减少内存损耗。

   例如:重写此方法,维持此映射只保存100个条目的稳定状态,在每次添加新条目时删除最旧的条目。

Java代码 
  1. private static final int MAX_ENTRIES = 100;  
  2. protected boolean removeEldestEntry(Map.Entry eldest) {  
  3.     return size() > MAX_ENTRIES;  
  4. }  

 来源:http://zhangshixi.iteye.com/blog/673789

参考:http://hi.baidu.com/yao1111yao/blog/item/3043e2f5657191f07709d7bb.html

部分修改。

 

 

使用LinkedHashMap构建LRU的Cache

http://tomyz0223.iteye.com/blog/1035686

基于LinkedHashMap实现LRU缓存调度算法原理及应用

http://woming66.iteye.com/blog/1284326

 

 

其实LinkedHashMap几乎和HashMap一样,不同的是它定义了一个Entry<K,V> header,这个header不是放在Table里,它是额外独立出来的。LinkedHashMap通过继承hashMap中的Entry<K,V>,并添加两个属性Entry<K,V>  before,after,和header结合起来组成一个双向链表,来实现按插入顺序或访问顺序排序。

<think>嗯,用户让我介绍一下Java集合中的LinkedHashMap,还要结合源码分析。首先,我得回忆一下LinkedHashMap的基本概念和它在Java集合框架中的位置。LinkedHashMap是HashMap的子类,所以它应该具有HashMap的所有特性,比如允许null键值,非同步等等。但它的特殊之处在于维护了一个双向链表,用来保持插入顺序或者访问顺序。这可能就是用户想深入了解的地方。 接下来,我需要考虑用户的需求。他们可能已经对HashMap有一定的了解,现在想进一步学习LinkedHashMap的工作原理和内部实现。所以,我应该先对比HashMap和LinkedHashMap的区别,强调LinkedHashMap的有序性。然后,可能需要讲解LinkedHashMap的数据结构,比如Entry节点的结构,双向链表是如何维护的。 然后,源码分析部分需要深入LinkedHashMap的关键方法,比如put、get、remove,以及如何维护访问顺序。比如,在HashMap的put方法中,LinkedHashMap可能重写了某些方法,比如afterNodeAccess和afterNodeInsertion,这些钩子方法的作用是什么。另外,访问顺序模式下,最近访问的节点会被移动到链表末尾,这在实现LRU缓存时很有用,这个点可能也需要提到。 用户可能还想知道LinkedHashMap如何实现迭代顺序的有序性。这时候需要分析迭代器的实现,可能是通过遍历双向链表而不是像HashMap那样遍历桶数组。此外,构造方法中的accessOrder参数的作用,以及如何影响元素顺序,这也是关键点。 另外,要注意到LinkedHashMap在实现LRU缓存时的应用。当accessOrder设置为true时,每次访问元素都会调整顺序,当达到容量时,会移除最老的元素。这部分可能需要结合removeEldestEntry方法的源码,说明如何扩展这个方法来控制缓存策略。 在结构上,应该先介绍LinkedHashMap的基本概念,然后数据结构,接着关键源码分析,最后应用场景。可能还需要给出一个简单的例子,比如如何用LinkedHashMap实现LRU缓存,这样用户更容易理解。 需要确认是否覆盖了主要的方法和内部类,比如Entry的结构,是否有新增的字段如before和after。同时,要注意源码的版本是否正确,假设是Java 8的源码,因为不同版本可能有差异。例如,在Java 8中,HashMap引入了树化结构,但LinkedHashMap仍然使用双向链表,这部分是否需要提及? 在讲解源码时,可能需要用代码块展示关键部分,比如Entry类的定义,以及afterNodeAccess方法的具体实现。但要注意不要粘贴过多代码,而是选择关键部分进行解释。 另外,用户可能对LinkedHashMap的性能感兴趣,比如与HashMap相比,插入、删除、访问的时间复杂度是否有变化。虽然LinkedHashMap维护了双向链表,但大多数操作的时间复杂度仍然是O(1),因为链表操作是常量时间的。 最后,总结LinkedHashMap的特点和适用场景,帮助用户理解何时应该选择LinkedHashMap而不是其他集合类。例如,需要保持插入顺序或访问顺序,或者需要实现简单的LRU缓存时。 需要确保解释清晰,逻辑连贯,避免技术术语过多导致理解困难。同时,结合源码分析时要抓住重点,展示关键代码部分并解释其作用,帮助用户理解内部机制。</think>### Java 集合之 LinkedHashMap 解析与源码分析 `LinkedHashMap` 是 `HashMap` 的子类,在保留 `HashMap` 高效查询能力的基础上,**通过双向链表维护元素的插入顺序或访问顺序**。它是实现 `LRU` 缓存策略的理想数据结构。 -- #### 核心特性 1. **有序性**:默认按插入顺序迭代,可配置为按访问顺序(最近访问的元素排在末尾)。 2. **性能**:查询、插入、删除的时间复杂度为 `O(1)`,略慢于 `HashMap`(需维护链表)。 3. **继承结构**:继承 `HashMap`,复用哈希表逻辑,重写链表维护相关方法。 --- ### 数据结构与关键源码 #### 1. Entry 结构扩展 `LinkedHashMap.Entry` 继承 `HashMap.Node`,**新增 `before` 和 `after` 指针**,形成双向链表。 ```java 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); } } ``` -- #### 2. 关键属性 - **head/tail**:维护链表的头尾节点。 - **accessOrder**:`true` 表示按访问顺序排序,`false`(默认)表示按插入顺序。 ```java transient LinkedHashMap.Entry<K,V> head; // 链表头(最老元素) transient LinkedHashMap.Entry<K,V> tail; // 链表尾(最新元素) final boolean accessOrder; // 顺序控制标志 ``` --- ### 核心方法源码分析 #### 1. 插入与链表维护 `LinkedHashMap` **未重写 `put()`**,直接复用 `HashMap` 的逻辑,但通过重写以下钩子方法维护链表: ```java // 插入新节点后,维护链表结构(可能触发删除最老元素) void afterNodeInsertion(boolean evict) { LinkedHashMap.Entry<K,V> first; if (evict && (first = head) != null && removeEldestEntry(first)) { removeNode(first.key, null, false, true); // 删除头节点(LRU 逻辑) } } // 是否删除最老元素(默认返回 false,需子类重写实现 LRU) protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false; } ``` --- #### 2. 访问顺序调整 当 `accessOrder=true` 时,调用 `get()` 或 `getOrDefault()` 会触发 `afterNodeAccess()`,将节点移到链表末尾。 ```java public V get(Object key) { Node<K,V> e; if ((e = getNode(key)) == null) return null; if (accessOrder) afterNodeAccess(e); // 调整链表顺序 return e.value; } // 将节点移动到链表尾部(最近访问) void afterNodeAccess(Node<K,V> e) { LinkedHashMap.Entry<K,V> last = tail; if (accessOrder && last != e) { LinkedHashMap.Entry<K,V> p = (Entry<K,V>)e; LinkedHashMap.Entry<K,V> 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++; } } ``` --- #### 3. 迭代器实现 `LinkedHashMap` 的迭代器直接遍历双向链表,而非哈希桶数组,**保证顺序性**。 ```java abstract class LinkedHashIterator { LinkedHashMap.Entry<K,V> next = head; // 从头节点开始 LinkedHashMap.Entry<K,V> current; // ... public final boolean hasNext() { return next != null; } final LinkedHashMap.Entry<K,V> nextNode() { LinkedHashMap.Entry<K,V> e = next; // ... current = e; next = e.after; // 通过 after 指针遍历 return e; } } ``` -- ### 应用场景:实现 LRU 缓存 通过重写 `removeEldestEntry()`,限制最大容量并删除最久未使用的元素。 ```java public class LRUCache<K, V> extends LinkedHashMap<K, V> { private final int maxCapacity; public LRUCache(int maxCapacity) { super(maxCapacity, 0.75f, true); // accessOrder=true this.maxCapacity = maxCapacity; } @Override protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return size() > maxCapacity; // 容量超限时删除最老元素 } } ``` --- ### 总结 - **有序性**:双向链表维护插入/访问顺序。 - **扩展性**:通过钩子方法(如 `afterNodeAccess`)实现行为定制。 - **高效性**:在 `HashMap` 基础上以少量性能代价换取顺序控制。 - **应用场景**:需要顺序迭代或实现类似 LRU 的缓存策略时优先选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值