原文: https://howtodoinjava.com/java/collections/linkedhashmap/
Java 中的LinkedHashMap
用于存储非常类似于HashMap
类的键值对。 区别在于,LinkedHashMap
会在HashMap
无序的情况下保持插入其中的元素的顺序。
在本 Java 集合教程中,我们将学习LinkedHashMap
类,其方法,用例和其他重要细节。
Table of Contents
1\. LinkedHashMap Hierarchy
2\. LinkedHashMap Features
3\. LinkedHashMap Constructors
4\. LinkedHashMap Methods
5\. LinkedHashMap Usecases
6\. LinkedHashMap Performance
7\. Concurrency in LinkedHashMap
8\. Conclusion
1. LinkedHashMap
层次结构
LinkedHashMap
类在 Java 中声明如下。 它扩展了HashMap
类 ,并且实现了Map
接口。 'K'
是键的类型,'V'
是键的映射值的类型。
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
{
//implementation
}
2. LinkedHashMap
特性
有关 Java LinkedHashMap
类的重要知识是:
- 它存储类似于
HashMap
的键值对。 - 它仅包含唯一键。 不允许重复的键。
- 它可能具有一个
null
键和多个null
值。 - 通过将元素添加到内部管理的双链表中,它可以保持插入的
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()
:它将从映射中删除所有键值对。void size()
:它返回此映射中存在的键/值对的数量。void isEmpty()
:如果此映射不包含键值映射,则返回true
。boolean containsKey(Object key)
:如果映射中存在指定的键,则返回'true'
。boolean containsValue(Object key)
:如果将指定值映射到映射中的至少一个键,则返回'true'
。Object get(Object key)
:检索由指定的key
映射的value
。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
维护插入顺序,这在我们要维护添加到Map
的对的顺序时非常有用。
有序访问权限的LinkedHashMap
通过覆盖removeEldestEntry()
方法来强加一个用于在将新映射添加到映射时自动删除陈旧的策略的方法,从而为创建 LRU 缓存特性提供了一个很好的起点。 这使您可以使用定义的某些条件使数据过期。
6. LinkedHashMap
的性能
HashMap
和LinkedHashMap
以恒定的时间执行添加,删除和包含的基本操作。 LinkedHashMap
的性能比HashMap
差一些,因为它必须维护一个双向链表,而HashMap
仅维护链表。
另一方面,在LinkedHashMap
情况下遍历Map
的速度比HashMap
略快,因为所需的时间仅与“大小”成比例。 对于HashMap
,迭代性能与“大小+容量”成正比。
7. LinkedHashMap
中的并发
HashMap
和LinkedHashMap
都也不是线程安全的,这意味着我们不能直接在多线程应用程序中使用它们以获得一致的结果。 我们应该使用Collections.synchronizedMap(Map map)
方法显式地同步它们。
Map<Integer, Integer> numbers = Collections.synchronizedMap(new LinkedHashMap<>());
Map<Integer, Integer> numbers = Collections.synchronizedMap(new HashMap<>());
对于HashMap
,更建议使用ConcurrentHashMap
,因为它提供的并发程度更高。
8. 总结
基于以上所有信息,我们可以说,在大多数情况下,最好选择HashMap
而不是LinkedHashMap
。 仅当我们有某些要求或用例需要保持添加到映射的元素顺序时,我们才更喜欢LinkedHashMap
。
两者在大多数现实用例中都提供几乎相同的性能。 当我们拥有大量数据时,则仅应考虑它们之间的权衡取舍。
学习愉快!
参考: