什么时候在java中使用linkedhashmap而不是hashmap?

Posted

技术标签:

【中文标题】什么时候在java中使用linkedhashmap而不是hashmap?【英文标题】:When to use linkedhashmap over hashmap in java? 【发布时间】:2014-12-24 17:32:46 【问题描述】:

在linkedhashmap和hashmap中选择的实际场景是什么?我已经完成了每个工作,得出的结论是linkedhashmap保持插入顺序,即元素将以与插入顺序相同的顺序检索,而hashmap不会保持顺序。 那么有人能说出在哪些实际场景中选择了其中一个集合框架以及为什么?

【问题讨论】:

Difference between HashMap, LinkedHashMap and TreeMap的可能重复 LinkedHashMap 的一个常见用途是 LRUCache:***.com/questions/23772102/… 【参考方案1】:

    LinkedHashMap 将按照条目放入映射的顺序进行迭代。

    null 允许在LinkedHashMap 中使用值。

    实现不同步,使用双链桶。

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

    LinkedHashMap 还为通过覆盖removeEldestEntry() 方法创建缓存对象提供了一个很好的起点。这使您可以创建一个 Cache 对象,该对象可以使用您定义的某些条件使数据过期。

    基于链表和散列数据结构,具有链表(想想 indexed-SkipList)能力,以插入树的方式存储数据。最适合实现 LRU(最近最少使用)。 LinkedHashMap 扩展 HashMap

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

LinkedHashMap 构造函数

LinkedHashMap( )

此构造函数构造一个空的插入排序的 LinkedHashMap 实例,具有默认的初始容量 (16) 和加载因子 (0.75)。

LinkedHashMap(int capacity)

此构造函数构造一个具有指定初始容量的空 LinkedHashMap。

 LinkedHashMap(int capacity, float fillRatio)

此构造函数构造一个具有指定初始容量和负载因子的空 LinkedHashMap。

LinkedHashMap(Map m)

此构造函数构造一个插入顺序的 Linked HashMap,其映射与指定的 Map 相同。

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);  

【讨论】:

他问的是实际用例,而不是它是如何工作的。你读过这个问题吗? 2.在 LinkedHashMap 中允许使用 null 值。 -> HashMap 也允许空值【参考方案2】:

购物车是一个现实生活中的例子,我们可以看到购物车编号与我们选择的商品的顺序是我们选择商品的顺序。所以地图可以是LinkedHashMap&lt;Cart Number Vs Item Chosen&gt;

【讨论】:

【参考方案3】: HashMap 绝对不保证迭代顺序。当添加新元素时,它甚至可以(并且将会)完全改变。 LinkedHashMap 将按照将条目放入映射中的顺序进行迭代 LinkedHashMap 还需要比 HashMap 更多的内存,因为这种排序功能。正如我之前所说,LinkedHashMap 使用双重 LinkedList 来保持元素的顺序。

【讨论】:

【参考方案4】:

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

但是,如果您查看使用地图的时间和地点,在许多情况下它只包含几个条目,不足以让不同实现的性能差异产生影响。

【讨论】:

【参考方案5】:

LinkedHashMap维护键的插入顺序,即键插入LinkedHashMap的顺序。另一方面,HashMap 不维护任何顺序或键或值。就性能而言,HashMapLinkedHashMap 之间没有太大区别,但是是的,LinkedHashMap 比 HashMap 具有更多的内存占用空间来维护用于跟踪键插入顺序的双向链表。

HashMapLinkedHashMap 具有更好的性能,因为LinkedHashMap 需要维护链表的费用。 LinkedHashMap 实现了一个普通的哈希表,但哈希表的键被存储为双向链表的额外好处。 他们的两种方法都不同步。 让我们看看他们的 API 文档:

HashMap 是一个哈希表,每个哈希槽中都有存储桶。

API 文档:

此实现为基本的 操作(get 和 put),假设散列函数分散 桶中的元素。对集合视图的迭代 所需时间与 HashMap 实例的“容量”成正比 (桶的数量)加上它的大小(键值的数量 映射)。因此,不要设置初始容量非常重要 如果迭代性能太高(或负载因子太低) 很重要。

LinkedHashMap是实现map接口的链表。作为 API文档中说:

Map接口的哈希表和链表实现,带有 可预测的迭代顺序。此实现不同于 HashMap 因为它维护一个双向链表,贯穿其所有 条目。这个链表定义了迭代顺序,即 通常是键插入地图的顺序 (插入顺序)。

【讨论】:

各自的实际场景是什么?为什么我们会选择它? 请浏览高亮部分。希望你能得到答案【参考方案6】:

我在工作中使用这些的一种方法是用于缓存的后端 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 方法为指定映射中的每个映射生成一个条目访问,按照指定映射的条目集迭代器提供键值映射的顺序。没有其他方法生成条目访问。特别是,collection-views 上的操作不会影响 backing map 的迭代顺序。

【讨论】:

以上是关于什么时候在java中使用linkedhashmap而不是hashmap?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们不能在java中的linkedHashMap中放置空键[关闭]

Java中最大的数据结构:LinkedHashMap 了解一下?

java性能优化之HashMap,LinkedHashMap,TreeMap读取大量数据效率的比较

多种方式解决Java控制台报错 java.util.LinkedHashMap cannot be cast to.....

LinkedHashMap如何转对象的问题

Java中HashMap和LinkedHashMap以及TreeMap的区别