在Java中什么时候应该使用LinkedHashMap而不是HashMap?

15
在选择LinkedHashMap和HashMap时,有哪些实际情况需要考虑?我已经研究了它们的工作原理,并得出结论:LinkedHashMap会保留插入顺序,即元素的检索顺序与插入顺序相同,而HashMap不会保持顺序。那么,有人能告诉我在什么实际场景下应该选择其中一个集合框架以及为什么吗?

3
可能是Difference between HashMap, LinkedHashMap and TreeMap的重复问题。 - Jimmar
2
LinkedHashMap 的一个常见用途是 LRUCache:https://dev59.com/questions/dGAg5IYBdhLWcg3wSpTD - Droid Teahouse
6个回答

16
  1. LinkedHashMap会按照元素放入映射的顺序进行迭代。

  2. null值可以在LinkedHashMap中使用。

  3. 该实现未同步且使用双向链接桶。

  4. LinkedHashMapHashMap非常相似,但它添加了对添加或访问项的顺序的感知,因此迭代顺序取决于构造参数而与插入顺序相同。

  5. LinkedHashMap还可以通过重写removeEldestEntry()方法提供一个创建缓存对象的绝佳起点。这使您可以创建一个缓存对象,该对象可以使用您定义的一些标准过期数据。

  6. 基于链表和哈希数据结构,具有按照插入顺序存储数据的链表(将索引式跳跃列表视为示例)。最适合实现LRU(最近最少使用)。 LinkedHashMap扩展自HashMap

LinkedHashMap维护映射中条目的链接列表,以它们被插入的顺序排列。这允许对映射进行按插入顺序的迭代。也就是说,在遍历LinkedHashMap的集合视图时,元素将按照它们被插入的顺序返回。如果将键再次插入LinkedHashMap中,则原始顺序将保留。这允许对映射进行按插入顺序的迭代。也就是说,当迭代LinkedHashMap时,元素将按照它们被插入的顺序返回。您还可以创建一个LinkedHashMap,使其按照最后访问的顺序返回其元素。

LinkedHashMap构造函数

LinkedHashMap( )

这个构造函数用默认的初始容量(16)和负载因子(0.75)构造一个空的按插入顺序排序的LinkedHashMap实例。

LinkedHashMap(int capacity)

这个构造函数创建一个指定初始容量的空LinkedHashMap。

 LinkedHashMap(int capacity, float fillRatio)

这个构造函数使用指定的初始容量和负载因子构造一个空的LinkedHashMap。

LinkedHashMap(Map m)

这个构造函数会构造一个按插入顺序排列的Linked HashMap,并将指定Map中的映射关系复制到新创建的HashMap中。

LinkedHashMap(int capacity, float fillRatio, boolean Order)

该构造函数使用指定的初始容量、负载因子和排序模式构造一个空的LinkedHashMap实例。

LinkedHashMap支持的重要方法

 Class clear( )

从地图中删除所有映射。

containsValue(object value )>

如果该映射将一个或多个键映射到指定的值,则返回true。

 get(Object key)

返回指定键映射到的值,如果此映射不包含该键的映射,则返回null。

removeEldestEntry(Map.Entry eldest)

以下是如何使用LinkedHashMap的示例:

Map<Integer, String> myLinkedHashMapObject = new LinkedHashMap<Integer, String>();  
myLinkedHashMapObject.put(3, "car");  
myLinkedHashMapObject.put(5, "bus");  
myLinkedHashMapObject.put(7, "nano");  
myLinkedHashMapObject.put(9, "innova");  
System.out.println("Modification Before" + myLinkedHashMapObject);  
System.out.println("Vehicle exists: " +myLinkedHashMapObject.containsKey(3));  
System.out.println("vehicle innova Exists: "+myLinkedHashMapObject.containsValue("innova"));  
System.out.println("Total number of vehicles: "+ myLinkedHashMapObject.size());  
System.out.println("Removing vehicle 9: " + myLinkedHashMapObject.remove(9));  
System.out.println("Removing vehicle 25 (does not exist): " + myLinkedHashMapObject.remove(25));  
System.out.println("LinkedHashMap After modification" + myLinkedHashMapObject);  

3
他问的是实际应用案例,而不是它的工作原理。你有读懂问题吗? - Shruti sharma
  1. LinkedHashMap 中允许 null 值。-> HashMap 也允许 null 值。
- Hưng Chu

10

购物车是一个现实生活中的例子,我们可以看到我们选择商品的顺序以及相应的购物车编号。因此,可以使用映射 LinkedHashMap<Cart Number Vs Item Chosen> 来表示。


6
  • HashMap 对迭代顺序不做任何保证。当新元素添加进来时,它的迭代顺序可以完全改变。
  • LinkedHashMap会按照元素添加的顺序进行迭代
  • 由于有序特性,LinkedHashMap比HashMap需要更多的内存。正如之前所说,LinkedHashMap使用双向链表来保持元素顺序。

4
LinkedHashMap 保持键的插入顺序,即键插入到 LinkedHashMap 中的顺序。另一方面,HashMap 不维护任何键或值的顺序。在性能方面,HashMapLinkedHashMap 之间没有太大的区别,但是 LinkedHashMap 具有更多的内存占用来维护双向链表,它用于跟踪键的插入顺序。 HashMap 的性能比 LinkedHashMap 更好,因为 LinkedHashMap 需要维护双向链表的开销。LinkedHashMap 实现了一个普通的哈希表,但是具有将哈希表的键存储为双向链表的附加优势。它们的方法都不是同步的。让我们看一下它们的 API 文档: HashMap 是一个哈希表,每个哈希槽中有桶。
API 文档:
这种实现为基本操作(get 和 put)提供恒定时间性能,假设散列函数将元素适当地分散在桶之间。对集合视图的迭代需要与 HashMap 实例的“容量”(桶的数量)及其大小(键值映射的数量)成比例的时间。因此,如果迭代性能很重要,则不要将初始容量设置得太高(或负载因子太低)。 LinkedHashMap 是实现 map 接口的链表。如 API 文档所述:
哈希表和链接列表实现了 Map 接口,并具有可预测的迭代顺序。这种实现与 HashMap 不同之处在于它维护通过其所有条目的双向链接列表。该链接列表定义了迭代顺序,通常是键插入到映射中的顺序(插入顺序)。

2
每个的实际应用场景是什么?为什么我们会选择它? - nikhil
1
请仔细阅读高亮部分,希望您能找到答案。 - ASHWANI KUMAR SINGH BISEN

4

大多数情况下,当使用 Map 时,您不关心插入顺序是否保持不变。如果您不关心,请使用 HashMap;如果您关心,请使用 LinkedHashMap。

然而,如果您看一下 Maps 的使用时间和地点,很多情况下它只包含了很少的条目,这些不足以使不同实现之间的性能差异产生影响。


1

我在工作中使用这些技术的一种方式是用于缓存后端REST查询。这些技术还具有按照某种顺序返回数据给客户端的附加优点。您可以在Oracle文档中了解更多相关信息:

https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html

这种技术特别适用于模块接收一个映射作为输入,复制它,然后返回结果,其顺序由副本的顺序决定。 (客户通常喜欢按照呈现顺序返回物品。)
提供了一个特殊的构造函数来创建链接哈希映射,其迭代顺序是其条目最后访问的顺序,从最近访问到最近(访问顺序)。 这种映射非常适合构建LRU缓存。 调用put,putIfAbsent,get,getOrDefault,compute,computeIfAbsent,computeIfPresent或merge方法会导致对应条目的访问(假设在调用完成后存在该条目)。 如果值被替换,则replace方法仅导致对条目的访问。 putAll方法为指定映射中的每个映射生成一个条目访问,顺序为指定映射的条目集迭代器提供的键值映射的顺序。没有其他方法生成条目访问。 特别地,集合视图上的操作不会影响支持映射的迭代顺序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接