双列集合接口Map
Map接口
Map 是 Java 集合框架中的一个核心接口,用于表示 键值对(Key-Value Pair) 的集合。Map 接口的实现类包括 HashMap、LinkedHashMap、TreeMap 等
特点
-
键值对存储
- Map 存储的是键值对,每个键(Key)映射到一个值(Value)。
- 键是唯一的,值可以重复
-
允许 null 键和 null 值
-
大多数 Map 实现类(如 HashMap 和 LinkedHashMap)允许键和值为 null。
-
Java 的 Objects.hashCode(Object o) 方法明确规定:若传入 null,返回 0。这是语言层面的约定,用于统一处理 null 的哈希逻辑
static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } //null 值的哈希值被定义为 0
-
TreeMap 不允许键为 null,但允许值为 null
-
-
无序性
- Map 不保证键值对的顺序(除了 LinkedHashMap 和 TreeMap)。
- HashMap 是无序的,LinkedHashMap 维护插入顺序,TreeMap 根据键的自然顺序或指定的比较器排序
-
非线程安全
- Map 的实现类(如 HashMap、LinkedHashMap 和 TreeMap)不是线程安全的
Map接口的常用方法
Map 接口定义了一系列操作键值对的方法,主要包括以下几类
-
添加键值对
V put(K key, V value)
:将指定的键值对添加到Map 中。如果键已经存在,则替换旧值并返回旧值;如果键不存在,则返回null
。void putAll(Map<? extends K, ? extends V> m)
:将指定Map 中的所有键值对添加到当前 Map 中。
2.2 删除键值对
V remove(Object key)
:移除指定键对应的键值对,并返回对应的值。如果键不存在,则返回null
。void clear()
:清空Map中的所有键值对。
2.3 修改键值对
V replace(K key, V value)
:替换指定键对应的值。如果键不存在,则返回 null。boolean replace(K key, V oldValue, V newValue)
:仅当指定键的当前值等于 oldValue时,才将其替换为 newValue。
2.4 查询键值对
V get(Object key)
:返回指定键对应的值。如果键不存在,则返回 null。boolean containsKey(Object key)
:判断Map 中是否包含指定的键。boolean containsValue(Object value)
:判断 Map 中是否包含指定的值。boolean isEmpty()
:判断 Map是否为空。int size()
:返回 Map 中键值对的数量。
2.5 遍历键值对
Set<K> keySet()
:返回 Map 中所有键的集合。Collection<V> values()
:返回 Map 中所有值的集合。Set<Map.Entry<K, V>> entrySet()
:返回 Map 中所有键值对的集合。
2.6 其他操作
default V getOrDefault(Object key, V defaultValue)
:返回指定键对应的值,如果键不存在,则返回 defaultValue。default void forEach(BiConsumer<? super K, ? super V> action)
:对 Map 中的每个键值对执行指定的操作
Map接口的常见实现类
- HashMap
- 基于哈希表实现,键值对无序。
- 允许键和值为 null。
- 添加、删除和查询操作的时间复杂度为 O(1)
- LinkedHashMap
- 基于哈希表和链表实现,维护键值对的插入顺序或访问顺序。
- 允许键和值为 null。
- 添加、删除和查询操作的时间复杂度为 O(1)
- TreeMap
- 基于红黑树实现,键值对根据键的自然顺序或指定的比较器排序。
- 不允许键为 null,但允许值为 null。
- 添加、删除和查询操作的时间复杂度为 O(log n)
- Hashtable
- 基于哈希表实现,键值对无序。
- 不允许键或值为 null。
- 线程安全(方法使用 synchronized 修饰)
- ConcurrentHashMap
- 基于分段锁实现,支持高并发的键值对操作。
- 不允许键或值为 null。
- 线程安全,性能优于 Hashtable
Map接口中的遍历操作
-
遍历键(Key)
-
Set<K> keySet()
:返回 Map 中所有键的集合 -
通过 keySet() 方法获取 Map 中所有键的集合,然后遍历键集合
Map<String, Integer> map = new HashMap<>(); map.put("Apple", 10); map.put("Banana", 20); map.put("Cherry", 30); // 遍历键 for (String key : map.keySet()) { System.out.println("Key: " + key); }
-
KeySet()方法返回的是个Set类型的单列集合,所以可以使用使用 Iterator
Iterator<String> iterator = map.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); System.out.println("Key: " + key); }
返回的Set类型的特点
-
Map.keySet() 返回的 Set 集合通常是 Map 实现类的内部类实例,而非通用的 HashSet 或 TreeSet
-
专用内部类:主流 Map 实现类(如 HashMap、TreeMap)会为 keySet() 方法定义一个内部类(如 HashMap.KeySet),该内部类直接引用 Map 中的键数据,不独立存储键值
-
对 Map 的修改(如增删键)会实时反映到 keySet() 返回的 Set 中,反之亦然(如通过 Set 删除键会同步修改原始 Map)
-
返回的 Set 通常不支持 add() 或 addAll() 方法(调用会抛出 UnsupportedOperationException),因为键的添加必须通过 Map.put() 方法完成
-
可以通过keySet() 进行删除,但不能添加
-
内部类实现的 Set 避免了创建独立集合的开销,直接依赖 Map 的存储结构,提升了遍历和查询效率
Map<Object, String> treeMap = new TreeMap<>(); treeMap.put(1,"1"); treeMap.put(2,"1"); treeMap.put(3,"1"); treeMap.put(-1,"1"); Set<Object> keyset = treeMap.keySet(); keyset.add(11); //❌java.lang.UnsupportedOperationException keyset.remove(3);//✔
-
-
遍历值(Value)
-
Collection<V> values()
:返回 Map 中所有值的集合 -
通过 values() 方法获取 Map 中所有值的集合,然后遍历值集合
// 遍历值 for (Integer value : map.values()) { System.out.println("Value: " + value); }
-
使用 Iterator
Iterator<Integer> iterator = map.values().iterator(); while (iterator.hasNext()) { Integer value = iterator.next(); System.out.println("Value: " + value); }
返回的Collection类型的特点
- 在 Java 的 Map 接口中,values() 方法返回的 Collection
通常是当前 Map 实现类的内部类实例 - values() 返回的 Collection 是 Map 内部定义的视图集合
- 视图集合与原始 Map 数据实时同步。例如,若 Map 中删除某个键值对,values() 返回的集合会立即体现这一变化
- 部分方法可能不支持(如 add()),调用时会抛出 UnsupportedOperationException,因为视图集合不独立存储数据,仅提供访问接口
- 与内部的Set一样,不能add可以remove
- 这个Collection集合中没有listIterator()方法,没有这个迭代器
-
-
遍历键值对(Entry)
-
Set<Map.Entry<K, V>> entrySet()
:返回 Map 中所有键值对的集合 -
通过 entrySet() 方法获取 Map 中所有键值对的集合,然后遍历键值对集合
-
如果使用 keySet() 遍历键,再通过 get(key) 获取值,每次获取值都需要一次查找操作
-
使用 entrySet() 直接获取键值对,避免了额外的查找操作,性能更高
-
同样的,使用entrySet()返回的集合可以删除不能添加
// 遍历键值对 for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); }
-
使用 Iterator
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, Integer> entry = iterator.next(); System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue()); }
Map.Entry<K, V> 是 Map 接口的内部接口,表示一个键值对。Map实现类的Node节点实现了该接口,它定义了以下方法
-
K getKey()
-
V getValue()
-
V setValue(V value)
for (Map.Entry entry :entrySet ) { Object key = entry.getKey(); Object value = entry.getValue(); entry.setValue(3); }
-
返回值特点
- entrySet() 返回的 Set 是 Map 的一个 视图集合,与底层数据结构(如数组、链表、红黑树)直接关联,而非独立的集合实例
- 这些内部类不实际存储数据,而是通过引用 Map 的原始数据实现高效遍历和操作,避免内存冗余
- 调用 add() 方法会抛出 UnsupportedOperationException,因为条目(Entry)必须通过 put(K, V) 方法插入到 Map 中
- 通过 entrySet() 对条目进行修改(如 setValue())会直接反映到原始 Map 中
-
使用 forEach() 方法
-
Java 8 引入了 forEach() 方法,可以更简洁地遍历 Map
-
遍历键值对
map.forEach((key, value) -> { System.out.println("Key: " + key + ", Value: " + value); });
-
遍历键
map.keySet().forEach(key -> { System.out.println("Key: " + key); });
-
遍历值
map.values().forEach(value -> { System.out.println("Value: " + value); });
-
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现