解析Java中1000个常用类:LinkedHashMap类,你学会了吗?

推荐一个我自己写的程序员在线工具站:
http://cxytools.com

提供一站式在线工具平台,专为程序员设计,包括时间日期、JSON处理、SQL格式化、随机字符串生成、UUID生成、随机数生成、文本Hash等功能,提升开发效率。

以下是正文。


在 Java 编程中,集合框架为我们提供了多种实现,以满足不同的需求。LinkedHashMap 类是 HashMap 的一个子类,它不仅保持了 HashMap 的基本功能,还通过双向链表实现了键值对的插入顺序。

1. LinkedHashMap 类概述

1.1 定义

LinkedHashMap 类位于 java.util 包中,是 HashMap 的一个具体实现。与 HashMap 不同,LinkedHashMap 通过维护一个双向链表来记录键值对的插入顺序或访问顺序,从而可以保证迭代时的顺序。

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> {
    // 构造方法和主要方法省略
}

1.2 主要特点

  • 有序性LinkedHashMap 保证了迭代顺序,可以是插入顺序或访问顺序。
  • 性能:与 HashMap 相比,性能稍微低一些,因为要维护双向链表,但仍然提供了常数时间的性能特性。
  • 允许 null 键和值:可以存储 null 键和值,与 HashMap 类似。

2. 常用方法

2.1 构造方法

LinkedHashMap 提供了多种构造方法,用于创建不同类型的映射。

// 创建一个空的 LinkedHashMap
LinkedHashMap<K,V> map = new LinkedHashMap<>();

// 创建一个具有指定初始容量和加载因子的 LinkedHashMap
LinkedHashMap<K,V> map = new LinkedHashMap<>(int initialCapacity, float loadFactor);

// 创建一个具有指定初始容量、加载因子和访问顺序的 LinkedHashMap
LinkedHashMap<K,V> map = new LinkedHashMap<>(int initialCapacity, float loadFactor, boolean accessOrder);

// 创建一个包含指定 Map 的 LinkedHashMap
LinkedHashMap<K,V> map = new LinkedHashMap<>(Map<? extends K, ? extends V> m);

2.2 put 方法

put 方法用于将指定的键值对放入映射中,如果映射中已存在该键,则更新其对应的值。

public V put(K key, V value)
示例
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("Alice", 30);
map.put("Bob", 25);
System.out.println(map); // 输出:{Alice=30, Bob=25}

2.3 get 方法

get 方法用于根据指定的键获取对应的值,如果映射中不包含该键,则返回 null

public V get(Object key)
示例
Integer age = map.get("Alice");
System.out.println("Alice's age: " + age); // 输出:Alice's age: 30

2.4 remove 方法

remove 方法用于根据指定的键从映射中移除键值对。

public V remove(Object key)
示例
map.remove("Bob");
System.out.println(map); // 输出:{Alice=30}

2.5 containsKey 方法

containsKey 方法用于判断映射中是否包含指定的键。

public boolean containsKey(Object key)
示例
boolean containsAlice = map.containsKey("Alice");
System.out.println("Contains Alice: " + containsAlice); // 输出:Contains Alice: true

2.6 containsValue 方法

containsValue 方法用于判断映射中是否包含指定的值。

public boolean containsValue(Object value)
示例
boolean containsAge30 = map.containsValue(30);
System.out.println("Contains value 30: " + containsAge30); // 输出:Contains value 30: true

2.7 size 方法

size 方法用于获取映射中的键值对数量。

public int size()
示例
int size = map.size();
System.out.println("Size: " + size); // 输出:Size: 1

2.8 clear 方法

clear 方法用于移除映射中的所有键值对。

public void clear()
示例
map.clear();
System.out.println(map); // 输出:{}

2.9 迭代器

LinkedHashMap 提供了 keySetentrySet 方法,分别用于获取键的集合和键值对的集合。

public Set<K> keySet()
public Set<Map.Entry<K,V>> entrySet()
示例
for (String key : map.keySet()) {
    System.out.println("Key: " + key);
}

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

3. 内部实现原理

LinkedHashMap 的内部实现主要基于哈希表和双向链表。它通过哈希表来存储键值对,并通过双向链表来维护键值对的顺序。

3.1 哈希表结构

LinkedHashMap 使用哈希表来存储键值对,哈希表中的每个节点除了存储键和值之外,还包含前驱和后继指针,用于维护双向链表。

3.2 双向链表

LinkedHashMap 通过双向链表来维护键值对的顺序。链表中的每个节点对应于哈希表中的一个节点,链表的头节点是第一个插入的键值对,尾节点是最后一个插入的键值对。

3.3 迭代顺序

LinkedHashMap 提供了两种迭代顺序:插入顺序和访问顺序。默认情况下,迭代顺序是插入顺序。如果在创建 LinkedHashMap 时指定了访问顺序,则每次访问键值对时,都会将该键值对移动到链表的末尾。

LinkedHashMap<K,V> map = new LinkedHashMap<>(initialCapacity, loadFactor, true); // true 表示按访问顺序

4. 实际应用

4.1 基本用法

LinkedHashMap 最常见的应用场景是需要保持键值对的插入顺序。

示例
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("Alice", 30);
map.put("Bob", 25);
map.put("Charlie", 35);

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

// 输出顺序为:
// Key: Alice, Value: 30
// Key: Bob, Value: 25
// Key: Charlie, Value: 35

4.2 实现 LRU 缓存

LinkedHashMap 可以通过指定访问顺序来实现简单的 LRU(最近最少使用)缓存。

示例
LinkedHashMap<String, Integer> lruCache = new LinkedHashMap<>(16, 0.75f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
        return size() > 5; // 当缓存大小超过5时移除最老的键值对
    }
};

lruCache.put("A", 1);
lruCache.put("B", 2);
lruCache.put("C", 3);
lruCache.put("D", 4);
lruCache.put("E", 5);

lruCache.get("A"); // 访问 A,使其成为最近使用的键
lruCache.put("F", 6); // 插入新的键值对 F

for (Map.Entry<String, Integer> entry : lruCache.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

// 输出顺序为:
// Key: B, Value: 2
// Key: C, Value: 3
// Key: D, Value: 4
// Key: E, Value: 5
// Key: A, Value: 1
// Key: F, Value: 6

4.3 迭代顺序控制

在某些情况下,我们可能需要对集合进行按访问顺序迭代,这在实现缓存或其他类似数据结构时非常有用。

示例
LinkedHashMap<String

, Integer> accessOrderMap = new LinkedHashMap<>(16, 0.75f, true);
accessOrderMap.put("A", 1);
accessOrderMap.put("B", 2);
accessOrderMap.put("C", 3);

accessOrderMap.get("A"); // 访问 A,使其成为最近使用的键
accessOrderMap.get("B"); // 访问 B,使其成为最近使用的键

for (Map.Entry<String, Integer> entry : accessOrderMap.entrySet()) {
    System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}

// 输出顺序为:
// Key: C, Value: 3
// Key: A, Value: 1
// Key: B, Value: 2

5. 性能考虑

在使用 LinkedHashMap 时,需要注意以下几点:

  • 空间开销:由于需要维护双向链表,LinkedHashMapHashMap 占用更多的内存。
  • 时间复杂度:插入、删除和访问操作的时间复杂度为 O(1),与 HashMap 相同,但由于链表操作,实际性能略低于 HashMap
  • 迭代性能LinkedHashMap 的迭代性能优于 HashMap,因为链表结构使得迭代时不需要跳跃。

6. 扩展阅读

6.1 HashMap

HashMapLinkedHashMap 的父类,用于实现基本的键值对映射。建议阅读 HashMap 的官方文档。

6.2 TreeMap

TreeMap 类基于红黑树实现,提供键的自然顺序或自定义顺序的映射。建议阅读 TreeMap 的官方文档。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

良月柒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值