第25节课-HashMap-笔记
文章摘要
本文介绍了Java中HashMap(哈希表)的基本概念和使用方法。HashMap是一种基于哈希算法的数据结构,以键值对形式存储数据,支持快速检索。主要内容包括:
- 哈希表的创建和基本操作:使用put方法添加/修改元素,remove方法删除元素,get方法查询元素
- 常用方法:size()获取元素数量,containsKey/containsValue检查存在性,keySet/values/entrySet获取数据集合
- 遍历方式:通过keySet()遍历键,values()遍历值,entrySet()遍历键值对
- 注意事项:键不能重复,哈希表无序存储,使用Map.Entry类型可以更方便操作键值对
哈希表适合处理需要快速查找的数据,但需要注意不保证元素顺序的特性。
00/ 前言
知识回顾
上节课学了动态数组,如何导入,如何创建。
接着,学了动态数组的常用方法。
然后,学习了for-i循环和for-each遍历动态数组。
先导课
数组可以通过索引来访问数组中的特定元素,那假设数据量变得非常庞大,再通过索引值来查看,就不切实际了。接下来我们通过学习哈希表解决这个问题。
01/ 创建HashMap
理解
定义:HashMap 是 java.util包中的一个类,是一个基于哈希算法实现的数据结构,因此又叫做哈希表。在HashMap中,数据以键值对的形式存储,每个键(key)映射到一个值(value),每个键值对称为映射项(Entry)。
无论HashMap中有多少数据,你都可以通过键来快速检索对应的值,这个过程非常快。
一家之言:
关键词: 键key 值 value
我的理解:给东西打标签,这里打标签就是键(key),通过键找到对应的东西,对应的东西就叫值(value),它们之间存在关系,在编程的角度理解就叫映射项。
哈希表的导入
import java.util.HashMap;
实例化一个哈希表
使用put方法添加元素,每个元素以字符串为键,整数为值。
HashMap<String, Integer> map = new HashMap<();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
System.out.println(map);注意事项
定义方面:
哈希表是个泛型类,所以在定义的时候要声明类型参数,
参数1决定key的类型
参数2决定值value的类型
打印方面:
使用println方法可以直接打印,值得注意的是打印的值不一定是按照顺序打印出来,因为哈希表只记录键和值的对应关系。
修改某一键的值
一个HashMap中,任何两个键都不相同,这保证了每个键都能独立地映射到一个值。
如果你尝试为已经存在的键插入一个新的值,原有的值将被新值替换。
// 创建一个空的 HashMap
HashMap<String, Integer> map = new HashMap<>();
// 添加元素
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 打印 HashMap
System.out.println("修改前:" + map);
// 修改"Cherry"对应的值
map.put("Cherry", 30);
System.out.println("修改后:" + map);
// 输出
修改前:{Apple=40, Cherry=20, Banana=10}
修改后:{Apple=40, Cherry=30, Banana=10}例题

答案
// 导入HashMap
import java.util.HashMap;
public class StudentInfo {public static void main(String[] args) {// 创建一个HashMap来存储学生信息,键为学号(long类型),值为姓名(String类型)HashMap<Long, String> studentMap = new HashMap<>();
// 添加三个学生的信息到HashMapstudentMap.put(123456L, "Alice");studentMap.put(789012L, "Bob");studentMap.put(345678L, "Charlie");
// 输出HashMap中存储的学生信息System.out.println(studentMap);}
}代码小结

02/ HashMap的常用方法
增 改 使用put方法
删 使用remove方法
查 使用get方法
补充:size方法 返回哈希表的元素数量
containsKey和containsValue 检查哈希表是否包含特定的键和值
keySet、values和entrySet 用于提取哈希表的所有键、值或映射项。
size方法
HashMap<String, Integer> map = new HashMap<>();
// 使用 put 方法添加元素
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 映射的大小
System.out.println("Size of map: " + map.size());
// 输出
Size of map: 3get方法
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);// get 键"Apple"对应的值
int numOfApple = map.get("Apple");
System.out.println(numOfApple);// get 不存在的键"苹果"
System.out.println(map.get("苹果"));
// 输出
40
null注意点:若指定的键不存在,则返回null
remove方法
remove() 方法用于删除HashMap中指定键对应的元素,并在删除后返回该键的值。
在删除过程中,若指定的键不在HashMap中,则返回null。
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
System.out.println(map);// 使用 remove 方法删除“Banana”元素,
// 并将对应的值存储在delNum变量中:
int delNum = map.remove("Banana");
System.out.println("删除了"+delNum+"个Banana");
System.out.println(map);// 删除不存在的键
System.out.println(map.remove("香蕉"));
// 输出
{Apple=40, Cherry=20, Banana=10}
删除了10个Banana
{Apple=40, Cherry=20}
null使用containsKey和containsValue判断键、值是否存在
你可以使用下面的方法检查HashMap中的元素:
containsKey()方法用于判断HashMap中,是否包含某一个指定的键containsValue()方法用于判断HashMap中,是否包含某一个指定的值
两种方法都返回一个布尔值:存在返回true,不存在则返回false
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 检查键是否存在
boolean isKey = map.containsKey("Cherry");
// 检查值是否存在
boolean isValue = map.containsValue(20);
System.out.println("map中包含了键'Cherry': " + isKey);
System.out.println("map中包含了值 20: " + isValue);
// 输出
map中包含了键'Cherry': true
map中包含了值 20: true获取键、值与键值对集合
以下方法可以帮助我们提取HashMap中的数据集合:
keySet()方法用于获取HashMap中所有的键;values()方法用于获取HashMap中所有的值;entrySet()方法用于获取HashMap中所有的键值对;HashMap<String, Integer> map = new HashMap<>(); map.put("Apple", 40); map.put("Banana", 10); map.put("Cherry", 20);// 获取映射的键集 System.out.println(map.keySet());// 获取映射的值集 System.out.println(map.values());// 获取映射的键值对集 System.out.println(map.entrySet());// 输出 [Apple, Cherry, Banana] [40, 20, 10] [Apple=40, Cherry=20, Banana=10]
Object 类型
在不知道keySet、values等方法返回值的具体类型时,我们如何用变量存储它们呢?
在Java中,几乎所有的类都直接或间接地继承了一个名为 Object 的类,它是Java类层次结构的根类。
因此我们可以使用Object类型的变量存储未知类型的数据:
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);// 获取映射的键集、值集和键值对集
Object keys = map.keySet();
Object values = map.values();
Object entry = map.entrySet();
System.out.println("Keys: " + keys);
System.out.println("Values: " + values);
System.out.println("Key-Value: " + entry);// 输出
Keys: [Apple, Cherry, Banana]
Values: [40, 20, 10]
Key-Value: [Apple=40, Cherry=20, Banana=10]例题


答案
import java.util.HashMap;public class MyTest {// 编写checkBackpack方法:public static void checkBackpack(HashMap<String, Integer> map, String target) {/* 判断map是否包含target:包含:输出 背包里有x瓶y不包含:输出两行,第一行"背包中没有xxx";第二行"当前背包物品:[xxx,xxx,xxx]"*/if (map.containsKey(target)) {System.out.println("背包里有" + map.get(target) + "瓶" + target);} else {System.out.println("背包中没有" + target);Object keys = map.keySet();System.out.println("当前背包物品:" + keys);}}public static void main(String[] args) {// 创建一个HashMap表示背包HashMap<String, Integer> backpack = new HashMap<>();backpack.put("恢复药水", 3);backpack.put("精力药水", 2);backpack.put("魔力药水", 1);// 调用方法检查背包中的商品checkBackpack(backpack, "精力药水");checkBackpack(backpack, "体力药水");}
}// 输出
背包里有2瓶精力药水
背包中没有体力药水
当前背包物品:[精力药水, 恢复药水, 魔力药水]代码小结

03/ 遍历HashMap
遍历HashMap的键
keySet()方法返回了一个包含键的集合,你可以使用for-each循环遍历它。这样就可以获取HashMap的每一个键:
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 使用for-each循环遍历HashMap的键:
for (String key : map.keySet()) {// 输出键System.out.println("Key: " + key);
}// 输出
Key: Apple
Key: Cherry
Key: Banana遍历HashMap的值
类似的结构,我们可以使用for-each循环遍历map.values()返回的每一个值:
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 使用for-each循环遍历HashMap的值:
for (Integer value : map.values()) {System.out.println("Value: " + value);
}// 输出
Value: 40
Value: 20
Value: 10遍历HashMap的键值对
方法1
可以使用for-each循环遍历map.entrySet()方法返回的映射项(键=值)。
因为我们不知道映射项的具体类型,所以用来遍历的变量需要设置为Object类型。
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 使用for-each循环遍历映射项
for (Object entry : map.entrySet()) {System.out.println(entry);
}// 输出
Apple=40
Cherry=20
Banana=10再谈Object类
因为Object是所有类型的父类,若用Object存储子类数据,无法使用该子类定义的方法。
这是因为子类可以继承父类的方法,但父类不能使用子类的方法。以String为例:
// 使用String存储的字符串,可以使用charAt方法 String test = "hello"; test.charAt(3) // 'l'// 使用Object存储的字符串,不可以使用charAt方法 Object test = "hello"; test.charAt(3) // 报错
方法2
在实际应用开发中,我们经常需要操作HashMap中的映射项以及它对应的方法。所以,我们不推荐直接使用Object类型遍历map.entrySet()。
那么存储映射项(键=值)的变量应该使用什么类型存储呢?
映射项(键=值)的对象名为Map.Entry。要想创建该类型的变量,我们需要导入java.util包中Map:
import java.util.HashMap;
// 从java.util中导入Map
import java.util.Map;
public class MyTest {public static void main(String[] args) {...}
}Map.Entry是一个包含两个类型参数的泛型类,它代表一个由键、值组成的映射项,声明语法为Map.Entry<键类型, 值类型> 变量名;
在for-each循环中,我们可以创建一个Map.Entry对象遍历map.entrySet返回的每一个键值对:
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 使用for-each循环遍历映射项
for (Map.Entry<String, Integer> entry : map.entrySet()) {System.out.println(entry);
}// 输出
Apple=40
Cherry=20
Banana=10Map.Entry的其他方法
不仅如此,Map.Entry还提供了单独提取键、值的方法:
getKey()方法用于返回映射项的键;getValue()方法用于返回映射项的值;
借助这两个方法,你可以同时遍历HashMap的键与值:
HashMap<String, Integer> map = new HashMap<>();
map.put("Apple", 40);
map.put("Banana", 10);
map.put("Cherry", 20);
// 使用for-each循环遍历映射项
for (Map.Entry<String, Integer> entry : map.entrySet()) {// 输出键System.out.println("Key: " + entry.getKey());// 输出值System.out.println("Value: " + entry.getValue());
}// 输出
Key: Apple
Value: 40
Key: Cherry
Value: 20
Key: Banana
Value: 10例题

答案
import java.util.HashMap;
// 从java.util导入Map
import java.util.Map;public class MyTest {// 修改checkBackpack方法public static void checkBackpack(HashMap<String, Integer> map, String target) {if (map.containsKey(target)) {System.out.println("背包里有" + map.get(target) + "瓶" + target);} else {System.out.println("背包中没有" + target);System.out.println("当前背包中有:");// 在for-each中使用Map.Entry对象遍历map的映射项for (Map.Entry<String, Integer> entry : map.entrySet()) {// 使用getKey、getValue方法获取键值String key = entry.getKey();int value = entry.getValue();// 按照"x瓶y"的格式输出,x是物品数量,y是物品名称System.out.println(value + "瓶" + key);}}}public static void main(String[] args) {// 创建一个HashMap表示背包HashMap<String, Integer> backpack = new HashMap<>();backpack.put("恢复药水", 3);backpack.put("精力药水", 2);backpack.put("魔力药水", 1);// 调用方法检查背包中的商品checkBackpack(backpack, "精力药水");checkBackpack(backpack, "体力药水");}
}// 输出
背包里有2瓶精力药水
背包中没有体力药水
当前背包中有:
2瓶精力药水
3瓶恢复药水
1瓶魔力药水代码小结

04/ 易错点总结

05/ 总结
1)理解哈希表的概念,如何导入,如何实例化。
2)理解哈希表的常用方法
3)如何遍历哈希表
