Module java.base
Package java.util

Class LinkedHashMap<K,V>

java.lang.Object
java.util.AbstractMap<K,V>
java.util.HashMap<K,V>
java.util.LinkedHashMap<K,V>
类型参数:
K - 此映射维护的键的类型
V - 映射值的类型
所有实现的接口:
Serializable, Cloneable, Map<K,V>, SequencedMap<K,V>

public class LinkedHashMap<K,V> extends HashMap<K,V> implements SequencedMap<K,V>

LinkedHashMapMap接口的哈希表和链表实现,具有明确定义的遍历顺序。此实现与HashMap不同之处在于,它维护一个双向链表,通过其所有条目。此链表定义了遍历顺序(迭代顺序),通常是键插入到映射中的顺序(插入顺序)。最近插入的条目(最老的)在最前面,最新的条目在最后。请注意,如果使用put方法将键重新插入到映射中,则不会影响遍历顺序。 (如果在调用m.containsKey(k)之前立即返回true时调用m.put(k, v),则键k将重新插入到映射m中。)此映射的反向顺序视图是相反的顺序,最新的条目首先出现,最老的条目最后出现。已经在映射中的条目的遍历顺序可以通过使用putFirstputLast方法来更改。

此实现使其客户端免受HashMap(和Hashtable)提供的未指定的、通常混乱的排序的影响,而不会增加与TreeMap相关的成本。它可用于生成具有与原始相同顺序的映射副本,而不考虑原始映射的实现:


     void foo(Map<String, Integer> m) {
         Map<String, Integer> copy = new LinkedHashMap<>(m);
         ...
     }
 
如果模块接受输入映射,复制它,并稍后返回其顺序由副本决定的结果,则此技术特别有用。 (客户通常希望以与呈现顺序相同的顺序返回事物。)

提供了一个特殊的构造函数,用于创建一个链接的哈希映射,其遍历顺序是其条目最后访问的顺序,从最近访问到最近访问(访问顺序)。这种映射非常适合构建LRU缓存。调用putputIfAbsentgetgetOrDefaultcomputecomputeIfAbsentcomputeIfPresentmerge方法会导致对相应条目的访问(假设在调用完成后条目存在)。只有在替换值时,replace方法才会访问条目。putAll方法为指定映射中提供的每个映射生成一个条目访问,顺序为指定映射的条目集迭代器提供的键-值映射的顺序。 没有其他方法生成条目访问。在反向视图上调用这些方法会生成对支持映射的条目的访问。请注意,在反向视图中,对条目的访问会将其首先移动到遍历顺序中。在映射或其反向排序视图上执行的putFirstlastEntry等显式定位方法执行定位操作,不会生成条目访问。对keySetvaluesentrySet视图或其序列化对应物上的操作不会影响支持映射的遍历顺序。

可以重写removeEldestEntry(Map.Entry)方法,以在向映射添加新映射时自动实施删除陈旧映射的策略。或者,由于“最老”的条目是遍历顺序中的第一个条目,程序可以通过使用firstEntrypollFirstEntry方法检查和删除陈旧映射。

此类提供了所有可选的MapSequencedMap操作,并允许空元素。与HashMap一样,它为基本操作(addcontainsremove)提供了恒定时间性能,假设哈希函数将元素正确分散在桶中。由于维护链表的额外开销,性能可能略低于HashMap,但有一个例外:对LinkedHashMap的集合视图进行迭代需要与映射的大小成正比的时间,而不考虑其容量。对HashMap的迭代可能更昂贵,需要与其容量成正比的时间。

链接哈希映射有两个影响其性能的参数:初始容量负载因子。它们的定义与HashMap完全相同。但是,请注意,对于此类选择过高的初始容量值的惩罚要比对HashMap的严重性小,因为此类的迭代时间不受容量的影响。

请注意,此实现未同步。如果多个线程同时访问链接哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部同步它。通常通过在自然封装映射的某个对象上同步来实现此目的。如果不存在这样的对象,则应在创建时使用Collections.synchronizedMap方法“包装”映射。这最好在创建时完成,以防止意外的未同步访问映射:

   Map m = Collections.synchronizedMap(new LinkedHashMap(...));
结构修改是添加或删除一个或多个映射的任何操作,或者在访问顺序链接哈希映射中影响迭代顺序。在插入顺序链接哈希映射中,仅更改已包含在映射中的键关联的值不是结构修改。在访问顺序链接哈希映射中,仅使用get查询映射是结构修改。)

通过此类的所有集合视图方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间内以任何方式对映射进行结构修改,除了通过迭代器自己的remove方法之外,迭代器将抛出ConcurrentModificationException。因此,在并发修改的情况下,迭代器会快速而干净地失败,而不是在未来的某个不确定时间冒险进行任意的、非确定性的行为。

请注意,迭代器的快速失败行为不能保证,因为一般来说,在未同步的并发修改的情况下,不可能做出任何硬性保证。快速失败迭代器基于尽力而为的基础抛出ConcurrentModificationException。因此,编写依赖此异常正确性的程序是错误的:迭代器的快速失败行为应仅用于检测错误。

通过此类的集合视图方法返回的分割器是延迟绑定快速失败的,并额外报告Spliterator.ORDERED

此类是Java集合框架的成员。

实现注意:
此类的所有集合视图方法返回的分割器是从相应集合的迭代器创建的。
自版本:
1.4
参见:
  • Constructor Details

    • LinkedHashMap

      public LinkedHashMap(int initialCapacity, float loadFactor)
      使用指定的初始容量和负载因子构造一个空的插入顺序LinkedHashMap实例。
      API注释:
      要创建一个初始容量适应预期映射数量的LinkedHashMap,请使用newLinkedHashMap
      参数:
      initialCapacity - 初始容量
      loadFactor - 负载因子
      抛出:
      IllegalArgumentException - 如果初始容量为负数或负载因子为非正数
    • LinkedHashMap

      public LinkedHashMap(int initialCapacity)
      使用指定的初始容量和默认负载因子(0.75)构造一个空的插入顺序LinkedHashMap实例。
      API注释:
      要创建一个初始容量适应预期映射数量的LinkedHashMap,请使用newLinkedHashMap
      参数:
      initialCapacity - 初始容量
      抛出:
      IllegalArgumentException - 如果初始容量为负数
    • LinkedHashMap

      public LinkedHashMap()
      使用默认初始容量(16)和负载因子(0.75)构造一个空的插入顺序LinkedHashMap实例。
    • LinkedHashMap

      public LinkedHashMap(Map<? extends K,? extends V> m)
      使用与指定地图相同的映射构造一个插入顺序LinkedHashMap实例。LinkedHashMap实例使用默认负载因子(0.75)和足以容纳指定地图中映射的初始容量。
      参数:
      m - 要将其映射放入此地图中的地图
      抛出:
      NullPointerException - 如果指定地图为null
    • LinkedHashMap

      public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
      使用指定的初始容量、负载因子和排序模式构造一个空的LinkedHashMap实例。
      参数:
      initialCapacity - 初始容量
      loadFactor - 负载因子
      accessOrder - 排序模式 - true表示访问顺序,false表示插入顺序
      抛出:
      IllegalArgumentException - 如果初始容量为负数或负载因子为非正数
  • Method Details

    • putFirst

      public V putFirst(K k, V v)
      如果给定映射尚未存在,则将给定映射插入地图中,或者如果已经存在则替换映射的值(可选操作)。此操作正常完成后,给定映射将存在于此地图中,并且它将是此地图遇到顺序中的第一个映射。

      如果此地图已经包含此键的映射,则必要时将重新定位映射,使其成为遇到顺序中的第一个。

      指定者:
      putFirst 在接口 SequencedMap<K,V>
      参数:
      k - 键
      v - 值
      返回:
      与k先前关联的值,如果没有则为null
      自:
      21
    • putLast

      public V putLast(K k, V v)
      如果给定映射尚未存在,则将给定映射插入地图中,或者如果已经存在则替换映射的值(可选操作)。此操作正常完成后,给定映射将存在于此地图中,并且它将是此地图遇到顺序中的最后一个映射。

      如果此地图已经包含此键的映射,则必要时将重新定位映射,使其成为遇到顺序中的最后一个。

      指定者:
      putLast 在接口 SequencedMap<K,V>
      参数:
      k - 键
      v - 值
      返回:
      与k先前关联的值,如果没有则为null
      自:
      21
    • containsValue

      public boolean containsValue(Object value)
      如果此地图将一个或多个键映射到指定值,则返回true
      指定者:
      containsValue 在接口 Map<K,V>
      覆盖:
      containsValue 在类 HashMap<K,V>
      参数:
      value - 要测试其在此地图中存在的值
      返回:
      如果此地图将一个或多个键映射到指定值,则返回true
    • get

      public V get(Object key)
      返回指定键映射到的值,如果此地图不包含该键的映射则返回null

      更正式地说,如果此地图包含从键k到值v的映射,使得(key==null ? k==null : key.equals(k)),则此方法返回v;否则返回null。(最多只能有一个这样的映射。)

      返回null并不一定表示该地图不包含该键的映射;也有可能地图明确将该键映射到null。可以使用containsKey操作来区分这两种情况。

      指定者:
      get 在接口 Map<K,V>
      覆盖:
      get 在类 HashMap<K,V>
      参数:
      key - 要返回其关联值的键
      返回:
      指定键映射到的值,如果此地图不包含该键的映射则返回null
      参见:
    • clear

      public void clear()
      从此地图中删除所有映射。此调用返回后,地图将为空。
      指定者:
      clear 在接口 Map<K,V>
      覆盖:
      clear 在类 HashMap<K,V>
    • removeEldestEntry

      protected boolean removeEldestEntry(Map.Entry<K,V> eldest)
      如果此地图应删除其最老的条目,则返回true。在向地图插入新条目后,putputAll会调用此方法。它为实现者提供了在添加新条目时每次删除最老条目的机会。如果地图表示缓存,则允许地图通过删除过时条目来减少内存消耗。

      示例用法:此覆盖将允许地图增长到100个条目,然后每次添加新条目时删除最老的条目,保持100个条目的稳定状态。

           private static final int MAX_ENTRIES = 100;
      
           protected boolean removeEldestEntry(Map.Entry eldest) {
              return size() > MAX_ENTRIES;
           }
       

      此方法通常不会以任何方式修改地图,而是允许地图根据其返回值自行修改。允许此方法直接修改地图,但如果这样做,它必须返回false(表示地图不应尝试进一步修改)。在此方法内部修改地图后返回true的效果是未指定的。

      此实现仅返回false(使此地图像普通地图一样运行 - 最老的元素永远不会被删除)。

      参数:
      eldest - 地图中最近插入的条目,或者如果这是一个访问顺序地图,则是最近访问的条目。如果在导致此调用的putputAll调用之前地图为空,则这将是刚刚插入的条目;换句话说,如果地图包含单个条目,则最老的条目也是最新的。
      返回:
      如果应从地图中删除最老的条目,则返回true;如果应保留,则返回false
    • keySet

      public Set<K> keySet()
      返回此映射中包含的键的Set视图。视图中键的遇到顺序与此映射的映射遇到顺序相匹配。该集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(除非通过迭代器自身的remove操作),则迭代的结果是未定义的。该集合支持元素移除,通过Iterator.removeSet.removeremoveAllretainAllclear操作从映射中移除相应的映射。它不支持addaddAll操作。其Spliterator通常提供比HashMap更快的顺序性能,但并行性能较差。
      指定者:
      keySet 在接口 Map<K,V>
      覆盖:
      keySet 在类 HashMap<K,V>
      返回:
      包含在此映射中的键的集合视图
    • sequencedKeySet

      public SequencedSet<K> sequencedKeySet()
      返回此映射的keySetSequencedSet视图。

      返回的视图具有与通过keySet方法返回的视图指定的相同特性。

      指定者:
      sequencedKeySet 在接口 SequencedMap<K,V>
      返回:
      此映射的keySetSequencedSet视图
      自:
      21
    • values

      public Collection<V> values()
      返回此映射中包含的值的Collection视图。视图中值的遇到顺序与此映射中条目的遇到顺序相匹配。该集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(除非通过迭代器自身的remove操作),则迭代的结果是未定义的。该集合支持元素移除,通过Iterator.removeCollection.removeremoveAllretainAllclear操作从映射中移除相应的映射。它不支持addaddAll操作。其Spliterator通常提供比HashMap更快的顺序性能,但并行性能较差。
      指定者:
      values 在接口 Map<K,V>
      覆盖:
      values 在类 HashMap<K,V>
      返回:
      包含在此映射中的值的视图
    • sequencedValues

      public SequencedCollection<V> sequencedValues()
      返回此映射的values集合的SequencedCollection视图。

      返回的视图具有与通过values方法返回的视图指定的相同特性。

      指定者:
      sequencedValues 在接口 SequencedMap<K,V>
      返回:
      此映射的values集合的SequencedCollection视图
      自:
      21
    • entrySet

      public Set<Map.Entry<K,V>> entrySet()
      返回此映射中包含的映射的Set视图。视图中的遇到顺序与此映射中条目的遇到顺序相匹配。该集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(除非通过迭代器自身的remove操作,或通过迭代器返回的映射条目上的setValue操作),则迭代的结果是未定义的。该集合支持元素移除,通过Iterator.removeSet.removeremoveAllretainAllclear操作从映射中移除相应的映射。它不支持addaddAll操作。其Spliterator通常提供比HashMap更快的顺序性能,但并行性能较差。
      指定者:
      entrySet 在接口 Map<K,V>
      覆盖:
      entrySet 在类 HashMap<K,V>
      返回:
      包含在此映射中的映射的集合视图
    • sequencedEntrySet

      public SequencedSet<Map.Entry<K,V>> sequencedEntrySet()
      返回此映射的entrySetSequencedSet视图。

      返回的视图具有与通过entrySet方法返回的视图指定的相同特性。

      指定者:
      sequencedEntrySet 在接口 SequencedMap<K,V>
      返回:
      此映射的entrySetSequencedSet视图
      自:
      21
    • newLinkedHashMap

      public static <K, V> LinkedHashMap<K,V> newLinkedHashMap(int numMappings)
      创建一个新的、空的、插入顺序的LinkedHashMap,适用于预期的映射数量。返回的映射使用默认负载因子0.75,并且其初始容量通常足够大,以便可以添加预期数量的映射而无需调整映射的大小。
      类型参数:
      K - 新映射维护的键的类型
      V - 映射值的类型
      参数:
      numMappings - 预期的映射数量
      返回:
      新创建的映射
      抛出:
      IllegalArgumentException - 如果numMappings为负
      自:
      19
    • reversed

      public SequencedMap<K,V> reversed()
      返回此映射的逆序视图。返回视图中映射的遇到顺序是此映射中映射的逆序。逆序排序会影响所有对顺序敏感的操作,包括对返回视图的集合的操作。如果实现允许对此视图进行修改,则修改将“写入”到底层映射。对底层映射的更改可能会或可能不会在此逆序视图中可见,这取决于实现。

      对逆序视图及其映射视图的修改是允许的,并将传播到此映射。此外,对此映射的修改将在逆序视图及其映射视图中可见。

      指定者:
      reversed 在接口 SequencedMap<K,V>
      返回:
      此映射的逆序视图
      自:
      21