Java中的LinkedHashMap用于存储键值对,与HashMap类非常相似。不同之处在于LinkedHashMap保持了元素插入的顺序,而HashMap是无序的。

在这个Java集合教程中,我们将学习LinkedHashMap类,它的方法,用途和其他重要细节。

1.LinkedHashMap层次结构

在Java中,LinkedHashMap类的声明如下。它扩展了HashMap类并实现了Map接口。这里的 ‘K’ 是键的类型,’V’ 是键的映射值的类型。

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> { //implementation } 

2.LinkedHashMap特点

关于Java LinkedHashMap类的重要事项有:

  • 它存储键值对,类似于HashMap。
  • 它只包含唯一的键。不允许重复的键。
  • 它可以有一个空键和多个空值。
  • 它通过将元素添加到内部管理的双向链表来保持插入的K,V对的顺序。

2.1. 插入顺序的LinkedHashMap

默认情况下,LinkedHashMap是按插入顺序排列的。它保持了元素添加时的顺序。在遍历LinkedHashMap时,我们得到的KV对的顺序与它们被添加的顺序完全相同。

LinkedHashMap<Integer, String> pairs = new LinkedHashMap<>(); pairs.put(1, "A"); pairs.put(2, "B"); pairs.put(3, "C"); pairs.put(4, "D"); pairs.forEach((key, value) -> { System.out.println("Key:"+ key + ", Value:" + value); }); 

输出:

Key:1, Value:A Key:2, Value:B Key:3, Value:C Key:4, Value:D 

2.2. 访问顺序的LinkedHashMap

在访问顺序的映射中,键根据上次使用LinkedHashMap的任何方法访问它们的顺序进行排序。调用put、putIfAbsent、get、getOrDefault、compute、computeIfAbsent、computeIfPresent或merge方法会导致对相应条目的访问。

键从最近访问的到最近访问的排序,并构建一个LRU缓存。

要创建访问顺序映射,LinkedHashMap具有一个特殊的构造函数参数。当设置为true时,LinkedHashMap维护访问顺序。

//3rd parameter set access order LinkedHashMap<Integer, String> pairs = new LinkedHashMap<>(2, .75f, true); pairs.put(1, "A"); pairs.put(2, "B"); pairs.put(3, "C"); pairs.put(4, "D"); //Access 3rd pair pairs.get(3); //Access 1st pair pairs.getOrDefault(2, "oops"); pairs.forEach((key, value) -> { System.out.println("Key:"+ key + ", Value:" + value); }); 

请注意输出,最近访问的条目如何移到顺序的末尾。

Key:1, Value:A Key:4, Value:D Key:3, Value:C Key:2, Value:B 

3.LinkedHashMap构造函数

LinkedHashMap有五种类型的构造函数:

  • LinkedHashMap():使用默认的初始容量(16)和负载因子(0.75)初始化默认的LinkedHashMap实现。
  • LinkedHashMap(int capacity):使用指定的容量和负载因子(0.75)初始化LinkedHashMap。
  • LinkedHashMap(Map map):使用与指定映射相同的映射初始化LinkedHashMap。
  • LinkedHashMap(int capacity, float fillRatio):使用指定的初始容量和负载因子初始化LinkedHashMap。
  • LinkedHashMap(int capacity, float fillRatio, boolean Order):初始化LinkedHashMap的容量和填充比,以及是否保持插入顺序或访问顺序。’true’启用访问顺序。’false’启用插入顺序,这是使用其他构造函数时的默认值行为。

4.LinkedHashMap方法

我们应该学习LinkedHashMap的重要方法如下:

  • void clear():从映射中删除所有键值对。
  • int size():返回映射中存在的键值对的数量。
  • boolean isEmpty():如果此映射不包含键值映射,则返回true。
  • boolean containsKey(Object key):如果映射中存在指定的键,则返回’true’。
  • boolean containsValue(Object key):如果指定值映射到映射中的至少一个键,则返回’true’。
  • Object get(Object key):检索由指定键映射的值。
  • Object remove(Object key):如果存在,从映射中删除指定键的键值对。
  • boolean removeEldestEntry(Map.Entry eldest):当映射从访问顺序映射中删除其最老的条目时,返回’true’。

4.1. Java LinkedHashMap示例

Java程序演示了使用linkedhashmap方法的用法。

import java.util.Iterator; import java.util.LinkedHashMap; public class LinkedHashMapExample { public static void main(String[] args) { //3rd parameter set access order LinkedHashMap<Integer, String> pairs = new LinkedHashMap<>(); pairs.put(1, "A"); pairs.put(2, "B"); pairs.put(3, "C"); String value = pairs.get(3); //get method System.out.println(value); value = pairs.getOrDefault(5, "oops"); //getOrDefault method System.out.println(value); //Iteration example Iterator<Integer> iterator = pairs.keySet().iterator(); while(iterator.hasNext()) { Integer key = iterator.next(); System.out.println("Key: " + key + ", Value: " + pairs.get(key)); } //Remove example pairs.remove(3); System.out.println(pairs); System.out.println(pairs.containsKey(1)); //containsKey method System.out.println(pairs.containsValue("B")); //containsValue method } } 

输出:

C oops Key: 1, Value: A Key: 2, Value: B Key: 3, Value: C {1=A, 2=B} true true 

5.LinkedHashMap用途

我们几乎可以在需要使用HashMap的所有情况下使用LinkedHashMap。在功能上,它可以非常透明地替代HashMap。

此外,LinkedHashMap保持插入顺序,使其非常有用,当我们希望保持添加到映射中的键值对的顺序时。

访问顺序的LinkedHashMap提供了创建LRU缓存功能的绝佳起点,通过覆盖removeEldestEntry()方法来强制实施在向映射添加新映射时自动删除陈旧数据的策略。这让你可以使用你定义的一些标准来过期数据。

6.LinkedHashMap性能

HashMap和LinkedHashMap都以常数时间性能执行添加、删除和包含的基本操作。LinkedHashMap的性能略低于HashMap,因为它必须维护一个双向链表,而HashMap只维护链表。

另一方面,在LinkedHashMap的情况下,循环Map要比HashMap稍快,因为所需的时间仅与“size”成正比。在HashMap的情况下,迭代性能与“size + capacity”成正比。

7.LinkedHashMap中的并发

无论是HashMap还是LinkedHashMap都不是线程安全的,这意味着我们不能在多线程应用程序中直接使用它们以获得一致的结果。我们应该使用Collections.synchronizedMap(Map map)方法明确地对它们进行同步。在HashMap的情况下,更建议使用ConcurrentHashMap,因为它提供了更高程度的并发性。

Map<Integer, Integer> numbers = Collections.synchronizedMap(new LinkedHashMap<>()); Map<Integer, Integer> numbers = Collections.synchronizedMap(new HashMap<>()); 

8.结论

根据上述所有信息,我们可以说,在大多数情况下,最好选择HashMap而不是LinkedHashMap。我们只有在需要保持元素添加到映射中的顺序的某些要求或用例时才会首选LinkedHashMap。

在大多数真实世界的用例中,它们提供几乎相同的性能。只有在处理大量数据的情况下,才需要考虑它们之间的权衡。