Java LinkedHashMap 与 HashMap

2025年3月27日 | 阅读 10 分钟

LinkedHashMap 与 HashMap 非常相似,它还有一个额外的功能,即维护插入元素的顺序。HashMap 提供了插入、删除和搜索元素的简便方法,但它不提供任何维护和跟踪插入元素顺序的方法。这时,LinkedHashMap 就派上用场了,它克服了这个问题。

HashMap 是 Java 中一个强大的数据结构,用于存储键值对。它通过关联的键来映射一个值。它允许我们存储 null 值和 null 键。它是 Java 集合的一个非同步类。而 LinkedHashMap 是 HashMap 的一个替代品,它支持维护元素的顺序。

LinkedHashMap 继承了 HashMap 类,并实现了 Java Collection 框架的 Map 接口。

HashMap

Java 中的 HashMap 是一个强大的数据结构,允许我们存储键值对。它允许我们存储 null 值对象。我们不能插入重复的键;如果我们尝试这样做,它将替换对应键的元素。我们可以轻松地对对象执行更新、删除等操作。HashMap 类位于 java.util 包中。

声明

HashMap 类声明如下

关于 HashMap 的一些要点如下:

  • 它包含键值对。
  • 它不能有重复的键。
  • 它最多可以有一个 null 键和多个 null 值。
  • 它是非同步的。
  • 它不提供维护元素顺序的方法。
  • Java HashMap 类的默认容量为 16,负载因子为 0.75。

示例

考虑下面的例子来实现 HashMap 并存储键值对

HashMapDemo.java

输出

Iterating Hashmap...
1 Chris
2 Morris
3 Sam
4 Cruise

LinkedHashMap

LinkedHashMap 类是 HashMap 类的替代品。它与 HashMap 类非常相似。由于它继承了 HashMap 类,因此它拥有 HashMap 类所有的属性和方法。此外,它还提供了一种简便的方法来维护元素的顺序。LinkedHashMap 继承了 HashMap 类并实现了 Map 接口。

声明

LinkedHashMap 类声明如下

关于 LinkedHashMap 的一些要点如下:

  • 它以键值对组合的形式存储值。
  • 它不能有重复的元素。
  • 它最多可以有一个 null 键和多个 null 值。
  • 它是非同步的。
  • 它提供了一种简便的方法来维护插入顺序

示例

考虑下面的例子来实现 LinkedHashMap 并存储其中的值

LinkedHashMapDemo.java

输出

100 John
101 Dev
102 Arya
103 Zoya

LinkedHashMap 和 HashMap 之间的区别

LinkedHashMap 是 HashMap 的一个替代品,具有一些额外的功能。以下是 LinkedHashMap 和 HashMap 之间的一些主要区别:

  • HashMap 和 LinkedHashMap 之间的主要区别在于元素的排序。LinkedHashMap 提供了一种排序和跟踪元素的方法。相比之下,HashMap 不支持元素的排序。在 LinkedHashMap 中,如果我们迭代一个元素,我们将按元素的插入顺序获取键。
  • HashMap 和 LinkedHashMap 都只允许一个 null 键和多个值。
  • HashMap 扩展了 AbstractMap 类并实现了 Map 接口,而 LinkedHashMap 扩展了 HashMap 类并实现了 Map 接口。
  • LinkedHashMap 和 HashMap 都是非同步的,但可以使用 Collections.synchronizedMap() 方法进行同步。
  • HashMap 使用一个桶来存储元素,桶是数组的索引,例如 bucket0 表示 index[0],bucket1 表示 index[1],依此类推。而 LinkedHashMap 使用与 HashMap 相同的内部实现,但除此之外,它还使用一个双向链表连接所有条目。这个链表对于排序元素很有用。
  • HashMap 比 LinkedHashMap 需要的内存少;因为 LinkedHashMap 使用与 HashMap 相同的实现过程;此外,它还使用一个双向链表来维护元素的顺序。
  • LinkedHashMap 和 HashMap 都提供相似的性能。

LinkedHashMap 和 HashMap 的比较表

考虑下面的 HashMap 和 LinkedHashMap 的比较表

属性HashMapLinkedHashMap
迭代顺序无保证顺序插入顺序
实现的 (接口)MapMap
Null 键/值只有一个 null 键 & 多个值只有一个 null 键 & 多个值
实施双向链表桶
同步非同步非同步
性能快速几乎与 HashMap 相似
扩展AbstractMap 类HashMap 类
内存低内存比 HashMap 占用更多内存。
线程安全非线程安全非线程安全

使用 LinkedHashMap 优于 HashMap 的优点

  1. 可预测的迭代顺序:与 HashMap 相比,LinkedHashMap 的一个重要优点是它保留了元素的插入顺序。当我们遍历 LinkedHashMap 时,元素将按照它们的插入顺序返回。在元素的顺序很重要的场合,这很有用。
  2. 有序操作的快速迭代:如果我们要在 Map 中访问或修改许多条目,并且访问这些条目的顺序很重要,那么 LinkedHashMap 可能比 HashMap 更高效。对于 HashMap,顺序不固定,因此我们必须对键或值进行排序才能获得特定的序列。
  3. 高效的有序插入:LinkedHashMap 维护一个表示整个条目集合的双向链表。因此,添加新条目的过程比 HashMap 略有开销,但仍然是 O(1)。此外,与事后尝试重新排序 HashMap 相比,插入 LinkedHashMap 通常成本更低。
  4. 适用于缓存:LinkedHashMap 可用于跟踪最近最少访问元素的那些数据结构,当需要移除最近最少访问的元素时。覆盖 removeEldestEntry() 方法允许我们控制何时从 Map 中移除最旧的条目(即最近最少访问的条目)。
  5. 清晰度和意图:明确使用 LinkedHashMap 会传达出希望保留插入顺序的信息,这可以使您的代码更易于理解。

使用 HashMap 优于 LinkedHashMap 的优点

  1. 较低的内存开销:HashMap 在大多数情况下比 LinkedHashMap 占用的内存少,因为它不需要通过额外的引用来维护插入顺序。
  2. 某些操作的更好性能:Map <String, Vehicle> zooAnimals; HashMap<String, Vehicle> 在某些操作上可能比 LinkedHashMap 性能更好,但不会维护插入顺序。HashMap 的内部实现可能无法为插入、检索和删除等操作提供足够的元素顺序。
  3. 简洁性和可预测性:在这种情况下,如果不需要元素的插入顺序,那么使用 HashMap 可以简化代码,使其更清晰易懂。使用 HashMap,例如维护访问顺序或与维护插入顺序相关的方法不再需要,代码更容易理解。
  4. 适用于顺序不重要的用例:如果元素的顺序对我们的情况不重要,那么我们可能会考虑使用 Map 而不是 List。例如,如果我们想存储键值对以便快速检索,并且检索顺序不重要;HashMap 是更好的选择。
  5. 潜在的更好性能:由于 LinkedHashMap 遵循双向链表条目,因此与 HashMap 相比,某些操作可能会产生轻微的性能损失。在不关心保持顺序的情况下,HashMap 可能会给出更好的结果。
  6. 并发性:如果我们只需要线程安全,ConcurrentHashMap(HashMap 的一个闪亮特性)比 LinkedHashMap 提供更好的并发性能。ConcurrentHashMap 的线程安全性是一个主要优势,而 LinkedHashMap 不支持线程安全但提供更好的可伸缩性。

何时使用 LinkedHashMap 和 HashMap?

我们将根据您的任务类型、性能、内存使用情况以及数据结构的典型行为,在 Java 应用程序中选择 LinkedHashMap 和 HashMap。

在以下情况使用 LinkedHashMap

  1. 顺序保留很重要:如果我们希望保留插入和检索的顺序,LinkedHashMap 是您的选择。列表中的元素以它们插入的相同顺序存储,这使其适用于需要维护可预测迭代顺序的情况。
  2. 实现 LRU 缓存:使用 LinkedHashMap 实现最近最少使用 (LRU) 缓存变得很方便。我们可以覆盖 removeEldestEntry() 方法来控制当缓存大小达到时如何驱逐最旧的条目(最近最少访问的条目)。这使其适用于涉及缓存的应用程序。
  3. 按插入顺序迭代元素:如果需要持续遍历 Map 条目并需要它们按最初插入的顺序排列,LinkedHashMap 比对 HashMap 中的键或值进行排序更方便、更直接。
  4. 保持清晰度和意图:将数据结构声明为 LinkedHashMap 会强调这种排序,并可能提高代码的可读性以及其他开发人员对您设计选择的理解。

在以下情况使用 HashMap

  1. 顺序不重要:如果元素的顺序不影响您的用例,并且检索、插入和删除键值对的速度是我们的首要关注点,那么我们应该考虑使用 HashMap。它比 C 更短、更简洁。因此,它具有更高的执行能力和更低的内存占用。
  2. 内存效率很重要:HashMap 通常比 LinkedHashMap 占用的内存少,因为它不需要保存指示插入顺序的指针。如果内存效率更重要或元素顺序不重要,HashMap 可能是更好的选择。
  3. 性能至关重要:在性能至关重要且不需要维护顺序的情况下,HashMap 由于其更简单的内部实现,可能会提供更好的性能。HashMap 在某些操作(如插入、检索和删除)上的表现可能优于 LinkedHashMap。
  4. 并发性:如果我们只需要线程安全,那么 ConcurrentHashMap(HashMap 的一个变体)比 LinkedHashMap 更可取。ConcurrentHashMap 提供更好的并发性能和可伸缩性,同时仍然提供 HashMap 的键值映射功能。

使用 LinkedHashMap 和 HashMap 的最佳实践

LinkedHashMap 的最佳实践

  1. 了解何时使用它:当需要保留插入或访问顺序时,使用 LinkedHashMap。如果您需要可预测的迭代顺序或涉及 LRU 缓存等数据结构,LinkedHashMap 也是一个不错的选择。
  2. 注意性能:虽然 LinkedHashMap 确保了插入顺序,但由于需要保存额外的指针,它可能具有更高的内存消耗和较慢的性能。请检查顺序保持的优点是否能抵消您特定情况下的性能影响。
  3. 用于缓存:LinkedHashMap 可以成为实现缓存机制的绝佳选择,特别是当需要其移除最近最少使用的元素的功能时。覆盖 removeEldestEntry() 方法以控制如何从 Map 中移除最旧的条目(即最近最少访问的条目)。
  4. 在代码中明确说明:当您选择 LinkedHashMap 时,请明确说明您的选择并说明为什么它比 HashMap 更好。这样,代码的可读性就提高了,其他开发人员也更容易理解您的设计决策。
  5. 考虑并发性:虽然 LinkedHashMap 本身不是线程安全的,但如果存在线程安全问题,可以在同步块中或与其他线程安全方法结合使用来同步它。然而,对于并发访问,可以使用 ConcurrentHashMap 代替。

HashMap 的最佳实践

  1. 了解性能特征:与 LinkedHashMap 相比,HashMap 通常具有更好的性能和更小的内存开销,因为其内部代码更简单。适用于顺序不重要且需要快速键值映射操作的 Map 请求。
  2. 当顺序不重要时优先选择:如果元素的顺序在您的情况下不重要,HashMap 是最佳选择。它简单高效,占用内存少,与 LinkedHashMap 相比性能更好。
  3. 适用于通用映射:HashMap 非常适合通用的键值映射,其中元素的顺序不重要。它广泛用于各种应用程序和库中,以实现高效的数据存储和检索。
  4. 考虑 ConcurrentHashMap 进行并发:如果我们只需要线程安全,请考虑使用 ConcurrentHashMap 而不是 HashMap。ConcurrentHashMap 在提供与 HashMap 类似的功能的同时,提供了更好的并发性能和可伸缩性。
  5. 在性能至关重要时使用:在性能至关重要且不需要维护顺序的情况下,HashMap 可能在插入、检索和删除元素等操作方面提供更好的性能。
  6. 注意未定义的迭代顺序:虽然 HashMap 不保证其元素在迭代期间的顺序,但重要的是要注意此行为,并避免在迭代 HashMap 时依赖任何特定顺序。

总结

总之,在 Java 中选择 LinkedHashMap 和 HashMap 取决于您的个人偏好、性能限制以及我们使用的数据结构的特性。

LinkedHashMap 通常在维护顺序很重要时更优。它保留插入顺序或查找顺序,使列表适用于需要可预测迭代顺序的情况。当您需要保留插入顺序、实现 LRU 缓存等数据结构,或者当清晰度和意图优先时,请选择 LinkedHashMap。

HashMap 是在顺序不重要时更受欢迎的选择,您的选择是内存效率、简洁性以及可能的更好性能。它比 LinkedHashMap 提供更好的操作以及内存降低。当顺序不重要、快速查找、插入和删除至关重要时,请将 HashMap 用于通用的键值映射。

最后,能够理解 LinkedHashMap 和 HashMap 的特性、优点和技术将帮助我们做出明智的选择,并选择适合您的 Java 应用程序的正确数据结构。无论是维护顺序还是提高性能和内存效率,我们都可以依赖 LinkedHashMap 或 HashMap,因为它们适合您的特定任务。