250. Java 集合 - 使用 Map 存储键值对
1. 🎯 键和值的基本关系规则
在 Map 中,**键(Key)和值(Value)**之间遵循两条非常重要的规则:
| 规则 | 说明 |
|---|---|
| 一个键只能绑定一个值 | 同一个键不能对应多个值 |
| 一个值可以被多个键绑定 | 不同的键可以指向同一个值 |
2. 🧩 Map 中集合结构的对应关系
因此,Map 中各部分的结构特点是这样的:
| 组成部分 | 特点 | 对应的数据结构 |
|---|---|---|
所有的键(Keys) | 无重复 | Set |
所有的键值对(Entries) | 无重复 | Set |
所有的值(Values) | 可以有重复 | Collection |
✅ 小结:键和值的组合方式决定了 Map 的整体结构特性!
3. 🛠️ Map 支持的基本操作
在使用 Map 时,你可以进行以下常见操作:
| 操作 | 描述 |
|---|---|
put(K key, V value) | 添加一个新的键值对(如果键已存在,会覆盖原值) |
get(K key) | 根据键获取对应的值 |
remove(K key) | 移除指定键及其对应的值 |
同时还支持一些集合常见操作,比如:
| 操作 | 描述 |
|---|---|
isEmpty() | 判断 Map 是否为空 |
size() | 获取 Map 中键值对数量 |
putAll(Map m) | 将另一个 Map 的内容全部放入当前 Map |
clear() | 清空 Map 中所有数据 |
4. 🚀 示例演示
让我们用一个简单的小例子快速感受一下:
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
Map<String, String> countryCapital = new HashMap<>();
// 添加元素
countryCapital.put("China", "Beijing");
countryCapital.put("Japan", "Tokyo");
countryCapital.put("USA", "Washington");
// 获取元素
System.out.println("Capital of China: " + countryCapital.get("China")); // Beijing
// 移除元素
countryCapital.remove("Japan");
// 判断是否为空
System.out.println("Is map empty? " + countryCapital.isEmpty()); // false
// 获取大小
System.out.println("Map size: " + countryCapital.size()); // 2
}
}
5. 🧠 深入:探索 Map 接口
在 JDK 中,Map 是建模"键值对结构"的核心接口。
✨ 小提醒
使用 Map 时,一定要谨慎选择键的类型,特别是:
- ⚡ 不推荐使用可变对象(
mutable object)作为键!
如果一个对象作为键,且在放入 Map 后被修改,那么:
- 它的
hashCode()或equals()可能变化 - 导致
Map无法正确找到它,甚至出现数据丢失现象!
❗ 例子:错误示范(使用可变对象做键)
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
class MutableKey {
String keyPart;
MutableKey(String keyPart) {
this.keyPart = keyPart;
}
@Override
public int hashCode() {
return Objects.hash(keyPart);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MutableKey that = (MutableKey) o;
return Objects.equals(keyPart, that.keyPart);
}
}
public class MutableKeyDemo {
public static void main(String[] args) {
Map<MutableKey, String> map = new HashMap<>();
MutableKey key = new MutableKey("initial");
map.put(key, "Value1");
System.out.println(map.get(key)); // 正常输出 Value1
// 修改 key 对象的内容
key.keyPart = "modified";
// 再次尝试获取
System.out.println(map.get(key)); // 输出 null!
}
}
- 原因:修改了
key的属性,导致其hashCode变化,Map再也找不到这个键了!
✅ 正确做法:使用不可变对象(如 String、Integer、Long)作为 Map 的键!
6. 🧩 Map.Entry:建模单个键值对
在 Map 中,键值对被抽象成了内部接口:Map.Entry<K,V>。
常见方法:
| 方法 | 描述 |
|---|---|
getKey() | 获取键 |
getValue() | 获取值 |
setValue(V value) | 更新对应的值 |
注意:
Entry对象是 Map 内容的视图。- 通过
Entry修改值,直接影响原 Map 中的数据! - 不能直接修改键,否则会破坏 Map 的结构!
7. 🎯 小结
| 要点 | 说明 |
|---|---|
| 一个键只能绑定一个值 | 一个值可以绑定多个键 |
| 键和值的集合结构不同 | 键是 Set,值是 Collection |
Map 接口定义了丰富的方法 | put、get、remove、size、clear 等 |
| 不要用可变对象做键 | 保持 Map 的稳定性 |
👀 培训互动问题
问题1:一个 Map 中可以有两个相同的键吗?
答案示例:不可以,键必须唯一,新值会覆盖旧值。
问题2:为什么不建议使用可变对象作为 Map 的键?
答案示例:因为对象变化后可能导致
hashCode改变,导致 Map 无法正确找到原本的键值对。
问题3:通过 Map.Entry 修改值,会影响原 Map 吗?
答案示例:会,Entry 只是 Map 中元素的一个视图,修改会直接同步到原 Map。