目录
[1、put(K key,V value)](#1、put(K key,V value))
[2、get(Object key)](#2、get(Object key))
[3、remove(Object key)](#3、remove(Object key))
[4、containsKey(Object key)](#4、containsKey(Object key))
[5、containsValue(Object value)](#5、containsValue(Object value))
[三、迭代器 Iterator](#三、迭代器 Iterator)
[① List 的迭代器](#① List 的迭代器)
[② Set 的迭代器](#② Set 的迭代器)
[③ Map 的迭代器](#③ Map 的迭代器)
[④ ListIterator 的特殊功能](#④ ListIterator 的特殊功能)
[四、Map 的主要实现类](#四、Map 的主要实现类)
4、LinkedHashMap------对应LinkedHashSet
前面我们提到了单列集合:

下面我们接着来看多列集合:
引言
想象一下
1990年代初的Java开发团队正在设计一个图书馆管理系统
他们需要一种数据结构来存储"书名-位置"这样的键值对关系
如果使用List,每次查找都需要遍历整个列表
如果使用Set,又只能存储单一值(去重)
于是,他们创造了Map接口------一种革命性的双列集合
就像图书馆的目录系统一样
通过书名(键)快速找到书架位置(值)
这个设计灵感来源于现实世界中的字典、电话簿、目录索引等
它们都遵循"通过一个标识符查找相关信息"的模式
一、Map接口概述
Map 是一种双列集合,用于存储键值对(key - value)
特点:
存储元素时,必须以键值对的方式进行
键key:键是唯一的,每个键只能对应一个值
值value:值可以重复,不同的键可以关联相同的值
查找:高效的,通过唯一的键值可以快速查到对应的value值
底层:哈希表或者红黑树等 实现的
好,废话不多说
Map的学习思路和前面单列集合差不多
我们直接来看它有什么方法

二、常见方法
1、put(K key,V value)
方法声明:
V put(K key,V value)
解释:
泛型中常见的类型参数命名约定:
K - Key(键)
V - Value(值)
E - Element(元素)
T - Type(类型)
N - Number(数字)
在 Map 中,V 代表值的类型,示例:
javaimport java.util.*; public class GenericTypeExample { public static void main(String[] args) { // Map<String, Integer> 中: // K = String(键的类型) // V = Integer(值的类型) Map<String, Integer> scoreMap = new HashMap<>(); // put 方法:V = Integer Integer oldValue = scoreMap.put("张三", 95); // V 作为参数和返回值类型 // get 方法:V = Integer Integer score = scoreMap.get("张三"); // V 作为返回值类型 // remove 方法:V = Integer Integer removedValue = scoreMap.remove("张三"); // V 作为返回值类型 // values 方法:返回 Collection<V>,这里 V = Integer Collection<Integer> scores = scoreMap.values(); // V 作为集合元素类型 } }
参数:
**key:**要关联的键,不能为null(某些实例例外)
value: 与键关联的值,可以为null
返回值:
返回被覆盖的值
如果 key 之前没有映射(即对应的值),则返回null
如果 key 已经存在,则返回被覆盖的之前的值
作用:
将指定的 键值对 添加到 Map 中
如果 键 已存在则替换旧值
**是否改变原始值:**是
注意事项:
键必须唯一,重复的键会覆盖原有值
多个键可以映射到同一个值
java
import java.util.*;
public class PutMethodExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
// 第一次添加,返回null
Integer oldValue1 = map.put("Apple", 5);
System.out.println("第一次添加Apple: " + oldValue1); // null
// 再次添加相同键,返回旧值
Integer oldValue2 = map.put("Apple", 10);
System.out.println("第二次添加Apple: " + oldValue2); // 5
System.out.println("当前Apple的值: " + map.get("Apple")); // 10
}
}
2、get(Object key)
方法声明:
V get(Object key)
参数:
key:要 获取 的键
返回值:
如果该键有映射的值,返回对应的值
如果没有,返回null
作用:
返回指定键所映射的 值
是否改变原始值:否
注意事项:
返回 null 可能表示键不存在,也可能表示键映射到 null 值
需要区分这两种情况的话,用 containsKey 方法(下面会提到)
java
import java.util.*;
public class GetMethodExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("name", "张三");
map.put("nullValue", null); // 显式存储null值
// 获取存在的键
String name = map.get("name");
System.out.println("name的值: " + name); // 张三
// 获取不存在的键
String notExist = map.get("age");
System.out.println("不存在的键: " + notExist); // null
// 获取显式存储为null的键
String nullValue = map.get("nullValue");
System.out.println("存储为null的值: " + nullValue); // null
// 如何区分"键不存在"和"键映射到null"
System.out.println("键是否存在: " + map.containsKey("age")); // false
System.out.println("键是否存在: " + map.containsKey("nullValue")); // true
}
}
3、remove(Object key)
方法声明:
V remove(Object key)
参数:
key:要 移除 的键
返回值:
如果该键有映射的值,返回被移除的 值
如果没有,则返回 null
作用:
从 Map 中移除指定键的映射关系,即删除这个 键值对
是否改变原始值:是
注意事项:
返回值同样存在 null 歧义问题
java
import java.util.*;
public class RemoveMethodExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Orange", null); // 存储null值
// 移除存在的键
Integer removedValue = map.remove("Apple");
System.out.println("移除的值: " + removedValue); // 5
System.out.println("移除后Map大小: " + map.size()); // 2
// 移除不存在的键
Integer notExist = map.remove("Grape");
System.out.println("移除不存在的键: " + notExist); // null
// 移除存储为null的键
Integer nullRemoved = map.remove("Orange");
System.out.println("移除null值: " + nullRemoved); // null
System.out.println("移除后Map大小: " + map.size()); // 1
}
}
4、containsKey(Object key)
方法声明:
boolean containsKey(Object key)
参数:
key:要 检查 的键
返回值:
如果 Map 包含指定键的映射关系,返回 true
否则返回 false
作用:
检查 Map 是否包含指定键
是否改变原始值:否
注意事项:
时间复杂度O(1)
java
import java.util.*;
public class ContainsKeyMethodExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
map.put("name", "张三");
map.put("address", null); // 显式存储null值
// 检查存在的键
System.out.println("包含name键: " + map.containsKey("name")); // true
// 检查不存在的键
System.out.println("包含age键: " + map.containsKey("age")); // false
// 检查存储为null的键
System.out.println("包含address键: " + map.containsKey("address")); // true
// 正确处理get()返回null的情况
String value = map.get("someKey");
if (map.containsKey("someKey")) {
System.out.println("键存在,值为: " + value);
} else {
System.out.println("键不存在");
}
}
}
5、containsValue(Object value)
方法声明:
boolean containsValue(Object value)
参数:
value:要 检查 的 值
返回值:
如果 Map 将一个或多个键映射到指定值,返回 true
否则返回 false
作用:
检查 Map 是否包含指定值
是否改变原始值:否
注意事项:
需要遍历所有值,时间复杂度O(n)
底层使用equals方法比较值
java
import java.util.*;
public class ContainsValueMethodExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Orange", 5); // 重复的值
// 检查存在的值
System.out.println("包含值5: " + map.containsValue(5)); // true
// 检查不存在的值
System.out.println("包含值10: " + map.containsValue(10)); // false
// 多个键映射到同一个值
System.out.println("值5出现次数: 多于1次");
}
}
6、size()
方法声明:
int size()
参数:
无
返回值**&**作用:
返回 Map 中键值对的数量
是否改变原始值:否
注意事项:
空 Map 的 size 为0
挺简单的懒得写了

7、isEmpty()
方法声明:
boolean isEmpty()
参数:
无
返回值:
如果 Map不包含键值对,返回 true
否则返回 false
作用:
检查 Map 是否为空
是否改变原始值:否
注意事项:
等价于 size() == 0
8、clear()
方法声明:
void clear()
参数:
无
返回值:
void
作用:
移除 Map 中所有的键值对
是否改变原始值:是
注意事项:
执行后 Map 为空
不会将 Map 引用设为 null
java
import java.util.*;
public class ClearMethodExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
System.out.println("清除前大小: " + map.size()); // 3
System.out.println("清除前是否为空: " + map.isEmpty()); // false
map.clear();
System.out.println("清除后大小: " + map.size()); // 0
System.out.println("清除后是否为空: " + map.isEmpty()); // true
// Map引用仍然有效,只是内容被清空
map.put("D", 4);
System.out.println("清空后重新添加: " + map.size()); // 1
}
}
9、keySet()
方法声明:
Set<K> keySet()
参数:
无
返回值:
Map 中所有键的 Set 视图
(就是把 Map 里的所有键拿出来,放到 Set 里给你看)
作用:
返回 Map 中所有键的集合
是否改变原始值:否
注意事项:
返回的 Set 与原来的 Map关联,修改会影响原来的 Map
不能通过 keySet 添加元素
可以通过 keySet 移除元素
切记不是在遍历里修改,遍历里修改元素用 Iterator
下面介绍完三个获取视图的方法再说这个问题
java
import java.util.*;
public class KeySetMethodExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Orange", 8);
// 获取所有键
Set<String> keys = map.keySet();
System.out.println("所有键: " + keys); // [Apple, Banana, Orange]
// 遍历所有键
for (String key : keys) {
System.out.println(key + " -> " + map.get(key));
}
// 通过keySet移除元素会影响原Map
keys.remove("Apple");
System.out.println("移除Apple后Map: " + map); // {Banana=3, Orange=8}
// 不能通过keySet添加元素
// keys.add("Grape"); // UnsupportedOperationException
}
}
10、values()
方法声明:
Collection<V> values()
参数:
无
返回值:
Map 中所有值的 Collection 视图
作用:
返回 Map 中所有值的集合
是否改变原始值:否
注意事项:
返回的 Collection 与原来的 Map关联
不能通过 values 添加或移除元素
值可以重复
java
import java.util.*;
public class ValuesMethodExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Orange", 5); // 重复的值
map.put("Grape", 3); // 重复的值
// 获取所有值
Collection<Integer> values = map.values();
System.out.println("所有值: " + values); // [5, 3, 5, 3]
// 统计值的出现次数
Map<Integer, Integer> countMap = new HashMap<>();
for (Integer value : values) {
countMap.put(value, countMap.getOrDefault(value, 0) + 1);
}
System.out.println("值的统计: " + countMap); // {3=2, 5=2}
}
}
11、entrySet()
方法声明:
Set<Map.Entry<K,V>> entrySet()
参数:
无
返回值:
Map 中所有键值对的 Set 视图
作用:
返回 Map 中所有键值对的集合
是否改变原始值:否
注意事项:
Map.Entry 是键值对的表示
可以通过 Entry 修改值
是遍历 Map 最高效的方式
java
import java.util.*;
public class EntrySetMethodExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Orange", 8);
// 获取所有键值对
Set<Map.Entry<String, Integer>> entries = map.entrySet();
// 遍历键值对(最高效的方式)
for (Map.Entry<String, Integer> entry : entries) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
// 通过Entry修改值
for (Map.Entry<String, Integer> entry : entries) {
if (entry.getKey().equals("Apple")) {
entry.setValue(10); // 修改值
}
}
System.out.println("修改后Map: " + map); // {Apple=10, Banana=3, Orange=8}
}
}
好,我们来补充一下 Iterator
三、迭代器 Iterator
主要是用来用统一的方式遍历不同类型的集合
是集合框架中的一种设计模式
可以想象成一个指针
它在集合的元素之间移动
逐个访问每个元素
1、核心方法:
①hasNext()
方法声明:
boolean hasNext()
返回值:
true:还有下一个元素
false:已经到达集合末尾
作用:
检查是否还有下一个元素
②next()
方法声明:
E next()
返回值:
集合中的下一个元素
作用:
返回下一个元素,并将迭代器向前移动一位
③remove()
方法声明:
void remove()
作用:
删除上一次 next() 返回的元素
注意事项:
必须在调用 next() 之后才能调用
每次 next() 调用之后只能调用一次
这是遍历过程中唯一安全的修改集合的方式
java
import java.util.*;
public class RemoveExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
System.out.println("原始列表: " + list);
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if ("B".equals(element) || "D".equals(element)) {
iterator.remove(); // 安全删除
}
}
System.out.println("删除后列表: " + list); // [A, C]
}
}
2、使用模式
java
import java.util.*;
public class BasicIteratorPattern {
public static void main(String[] args) {
Collection<String> collection = Arrays.asList("Apple", "Banana", "Orange");
// 1. 获取迭代器
Iterator<String> iterator = collection.iterator();
// 2. 遍历元素的标准模式
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}
}
}
3、不同集合的迭代器
回到之前的问题
keySet、values、entrySet这哥仨是可以调用迭代器在遍历里修改元素的
为什么可以呢?
注意看他们仨的方法声明
两个返回Set,而Set继承自Collection
一个返回Collection
而Collection 实现了Iterable接口
所以可以调用 Iterator

① List 的迭代器
java
import java.util.*;
public class ListIteratorExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
// 普通 Iterator
Iterator<String> iterator = list.iterator();
System.out.println("普通迭代器遍历:");
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// ListIterator(功能更强大)
ListIterator<String> listIterator = list.listIterator();
System.out.println("\nListIterator 正向遍历:");
while (listIterator.hasNext()) {
int index = listIterator.nextIndex();
String element = listIterator.next();
System.out.println("索引 " + index + ": " + element);
}
System.out.println("\nListIterator 反向遍历:");
while (listIterator.hasPrevious()) {
int index = listIterator.previousIndex();
String element = listIterator.previous();
System.out.println("索引 " + index + ": " + element);
}
}
}
② Set 的迭代器
java
import java.util.*;
public class SetIteratorExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>(Arrays.asList("Apple", "Banana", "Orange"));
// Set 的迭代器(无序)
Iterator<String> iterator = set.iterator();
System.out.println("HashSet 元素:");
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
③ Map
Map本身不可以使用迭代器,原因:
- Map接口没有实现Iterable接口
- Map是键值对的映射关系,不是线性集合结构
- 没有直接的iterator()方法
所以 Map 就用刚才那哥仨简介调用迭代器
java
import java.util.*;
public class MapIteratorExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 5);
map.put("Banana", 3);
map.put("Orange", 8);
// Map 本身没有 Iterator,但可以通过视图获取
System.out.println("通过 keySet 遍历:");
Iterator<String> keyIterator = map.keySet().iterator();
while (keyIterator.hasNext()) {
String key = keyIterator.next();
System.out.println(key + " -> " + map.get(key));
}
System.out.println("\n通过 entrySet 遍历:");
Iterator<Map.Entry<String, Integer>> entryIterator = map.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<String, Integer> entry = entryIterator.next();
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
④ ListIterator 的特殊功能
ListIterator 是 Iterator 的子接口,专门为 List 设计,提供更多功能:
java
import java.util.*;
public class ListIteratorFeatures {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
System.out.println("原始列表: " + list);
ListIterator<String> listIterator = list.listIterator();
// 1. 正向遍历
System.out.println("正向遍历:");
while (listIterator.hasNext()) {
int index = listIterator.nextIndex();
String element = listIterator.next();
System.out.println("索引 " + index + ": " + element);
}
// 2. 反向遍历
System.out.println("\n反向遍历:");
while (listIterator.hasPrevious()) {
int index = listIterator.previousIndex();
String element = listIterator.previous();
System.out.println("索引 " + index + ": " + element);
}
// 3. 在当前位置添加元素
listIterator.next(); // 移动到第一个元素
listIterator.add("X"); // 在当前位置前添加
System.out.println("\n添加X后: " + list); // [X, A, B, C]
// 4. 设置当前元素
listIterator.next(); // 移动到A
listIterator.set("Y"); // 替换A为Y
System.out.println("替换后: " + list); // [X, Y, B, C]
}
}
四、Map 的主要实现类
1、HashMap------对应HashSet
底层:
哈希表
特点:
无序
存储顺序不保证一致
键唯一,所以key的自定义类要注意hashCode和equals方法的重写
值可以重复
线程不安全
null:
key 可以为null,只能有一个
value 可以为null,可以有多个
注意:
HashMap在添加值的时候先调用hashCode方法,再调用equals方法
HashSet底层用到了HashMap
java
import java.util.*;
public class HashMapExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
// HashMap允许null键和null值
map.put(null, 1); // null键
map.put("nullValue", null); // null值
map.put(null, 2); // 覆盖null键的值
System.out.println("HashMap: " + map);
System.out.println("null键的值: " + map.get(null)); // 2
}
}
2、Hashtable------对应Vector
底层:
哈希表
特点:
存储顺序不保证一致
键唯一,所以key的自定义类要注意hashCode和equals方法的重写
值可以重复
线程安全
null:
key 和 value 都不能为null
java
import java.util.*;
public class HashtableExample {
public static void main(String[] args) {
Map<String, Integer> map = new Hashtable<>();
map.put("Apple", 1);
map.put("Banana", 2);
// Hashtable不允许null键和null值
// map.put(null, 1); // NullPointerException
// map.put("nullValue", null); // NullPointerException
System.out.println("Hashtable: " + map);
}
}
3、TreeMap------对应TreeSet
底层:
红黑树
实现了 SortedMap 接口,所以元素的顺序会自动排序
特点:
有序
对key值排序,自然排序和比较器排序(就近原则:比较器排序 > 自然排序)
键唯一,所以key的自定义类要注意hashCode和equals方法的重写
值可以重复
线程不安全,可以通过其他方式解决线程安全问题
null:
key 不能为null,会抛出空指针异常
value 可以为null,可以有多个
java
import java.util.*;
public class TreeMapExample {
public static void main(String[] args) {
Map<String, Integer> map = new TreeMap<>();
map.put("Banana", 2);
map.put("Apple", 1);
map.put("Cherry", 3);
// 自动按键排序
System.out.println("TreeMap: " + map); // {Apple=1, Banana=2, Cherry=3}
}
}
4、LinkedHashMap------对应LinkedHashSet
底层:
哈希表 和 双向链表
特点:
按照存入顺序排序
键唯一,所以key的自定义类要注意hashCode和equals方法的重写
值可以重复
线程不安全,可以通过其他方式解决线程安全问题
null:
key 能为null,只能有一个
value 可以为null,可以有多个
java
import java.util.*;
public class LinkedHashMapExample {
public static void main(String[] args) {
Map<String, Integer> map = new LinkedHashMap<>();
map.put("First", 1);
map.put("Second", 2);
map.put("Third", 3);
// 保持插入顺序
System.out.println("LinkedHashMap: " + map); // {First=1, Second=2, Third=3}
// 访问不会改变顺序
map.get("Second");
System.out.println("访问后: " + map); // 顺序不变
}
}
