Просмотр исходного кода

docs: 更新20260731课堂笔记及README,同步代码变更——新增Map遍历(Demo04)与HashMap底层原理(Demo05),补充Demo03 Map方法

WanJL 3 недель назад
Родитель
Сommit
951d673ab2

+ 2 - 2
README.md

@@ -36,7 +36,7 @@
 | 2026-07-28 | [Java 异常处理:异常概念、Throwable 体系结构、编译期/运行时异常、JVM 默认处理、try-catch 多 catch 块、异常常用方法、finally 资源关闭、throws 抛出、鲁棒性;自定义异常、throw/throws;Object 类:equals/hashCode/toString 重写、Objects 工具类;课后作业回顾 — String 分割去重/统计、LocalDate 天数差计算](./课堂笔记/01-JavaSE基础-笔记/20260728-笔记.md) |
 | 2026-07-29 | [包装类(Wrapper Classes)+ 集合框架入门(Collection Framework)+ 泛型(Generics):基本类型与包装类对应关系、装箱与拆箱、自动装箱/拆箱、包装类优势、缓存机制、Bean 类应用;集合 vs 数组、体系结构(Collection/List/Set/Map)、线性表数据结构(栈/队列/数组/链表)、ArrayList 底层实现详解(默认容量10、扩容机制、三个构造方法、size vs capacity、trimToSize/ensureCapacity/grow 1.5倍扩容公式、位运算符 >> <<)、ArrayList 常用方法速查;泛型概念与好处、泛型定义格式、通配符 ? / ? extends T、自定义泛型类、有界类型参数、练习参考答案(Student toString/equals/hashCode、泛型 vs 原始类型)](./课堂笔记/01-JavaSE基础-笔记/20260729-笔记.md) |
 | 2026-07-30 | [List.of / LinkedList / 自定义链表 / ArrayList 练习](./课堂笔记/01-JavaSE基础-笔记/20260730-笔记.md) |
-| 2026-07-31 | [LinkedList 多接口形态(List/Queue/Deque)+ Iterator 迭代器 + Map集合入门(HashMap)](./课堂笔记/01-JavaSE基础-笔记/20260731-笔记.md) |
+| 2026-07-31 | [LinkedList 多接口形态(List/Queue/Deque)+ Iterator 迭代器 + Map集合(入门/遍历/底层原理)](./课堂笔记/01-JavaSE基础-笔记/20260731-笔记.md) |
 
 ## 二、授课代码
 
@@ -59,7 +59,7 @@
 | 2026-07-28 | 异常处理(Demo01~Demo04 + Person+AgeOutOfBoundsException) + Object类(Demo01+Person 重写equals/hashCode/toString) + 课后作业回顾(String工具 + 日期数学) + Exercises | `c260728` | [`course/api`](./授课代码/c260728/src/course/api/) / [`course/exception`](./授课代码/c260728/src/course/exception/) / [`homework260727`](./授课代码/c260728/src/homework260727/) / [`exercise/exercise01`](./授课代码/c260728/src/exercise/exercise01/) / [`exercise/exercise07`](./授课代码/c260728/src/exercise/exercise07/) |
 | 2026-07-29 | 包装类 + 集合框架入门 + 泛型(Generics):装箱/拆箱、自动装箱/拆箱、包装类在 Bean 中的应用;集合 vs 数组、体系结构、线性表数据结构、ArrayList 底层实现详解(默认容量10、扩容机制、三个构造方法、size vs capacity、trimToSize/ensureCapacity/grow 1.5倍扩容公式、位移运算符)、ArrayList 常用方法速查;泛型概念与好处、定义格式、通配符、自定义泛型类、有界类型参数、练习参考答案(Student 类重写 toString/equals/hashCode、泛型 vs 原始类型) | `c260729` | [`course/packaging`](./授课代码/c260729/src/course/packaging/) / [`course/collection`](./授课代码/c260729/src/course/collection/) / [`exercises/exercise01`](./授课代码/c260729/src/exericse/exericse01/) / [`exercises/exercise02`](./授课代码/c260729/src/exericse/exericse02/) |
 | 2026-07-30 | List.of() 不可变集合 + LinkedList 双链表理论 + 手写单链表 MyLinked + Student 课程管理练习 (ArrayList 常用操作) + 课后作业回顾手写 MyArrayList | `c260730` | [`course`](./授课代码/c260730/src/course/) / [`exericse/exericse01`](./授课代码/c260730/src/exericse/exericse01/) / [`homework0729/p4`](./授课代码/c260730/src/homework0729/p4/) |
-| 2026-07-31 | LinkedList 多接口形态(List / Queue / Deque)+ Iterator 迭代器遍历(ArrayList/LinkedList 迭代器)+ Map集合入门(HashMap:put/keySet/values) | `c260731` | [`course`](./授课代码/c260731/src/course/) |
+| 2026-07-31 | LinkedList 多接口形态(List / Queue / Deque)+ Iterator 迭代器遍历(ArrayList/LinkedList 迭代器)+ Map集合入门(HashMap:put/keySet/values/containsKey)、遍历(keySet+get / entrySet)、HashMap底层原理(数组+链表/红黑树、hashCode/equals、5个关键常量) | `c260731` | [`course`](./授课代码/c260731/src/course/) |
 
 ## 三、课堂练习题
 

+ 18 - 6
授课代码/c260731/src/course/Demo03.java

@@ -25,12 +25,21 @@ public class Demo03 {
         Map的值(Value) 可以理解成是数组的元素,元素是可以重复的,元素之间的顺序,是根据索引来确定的。
 
         Map常用的方法:
-            V get(Object key)   根据Key键 获取 Value值
-            V put(K key, V value)   向Map集合中添加元素(键值对)
-            Set<K> keySet()     调用这个方法后,会把当前Map集合中的所有Key组成一个Set集合(无序的单列集合)
-            Collection<V> values(); 把所有的Value值,组合成一个单列集合
-            Set<Map.Entry<K, V>> entrySet();    返回一个单列Set集合,集合集合中每个元素都是一个Map的内部类(Entry)对象。
-            Entry就是有Map的键值对组成的一个类型。
+            基本使用:
+                V put(K key, V value)   向Map集合中添加元素(键值对)
+                boolean containsKey(Object key) 判断Map集合中是否包含指定的key键
+                boolean containsValue(Object value) 判断Map集合中是否包含指定的value值
+                void clear()    清空集合,移除所有的键值对元素
+                boolean isEmpty()   判断集合是否为空值
+                int size()  返回集合中的有效元素个数
+
+            获取元素:
+                V get(Object key)   根据Key键 获取 Value值
+                Set<K> keySet()     调用这个方法后,会把当前Map集合中的所有Key组成一个Set集合(无序的单列集合)
+                Collection<V> values(); 把所有的Value值,组合成一个单列集合
+                Set<Map.Entry<K, V>> entrySet();    返回一个单列Set集合,集合集合中每个元素都是一个Map的内部类(Entry)对象。
+                Entry就是有Map的键值对组成的一个类型。
+
 
         Map中最常用的实现类:HashMap
         先使用:
@@ -67,6 +76,9 @@ public class Demo03 {
         System.out.println(map1);
         System.out.println(map);
 
+
+
+
     }
 
 

+ 60 - 0
授课代码/c260731/src/course/Demo04.java

@@ -0,0 +1,60 @@
+package course;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo04
+ * @description 遍历Map集合
+ * @create 2026/7/31
+ */
+public class Demo04 {
+    /*
+    Map的遍历方式一:
+        Map存入的元素都是成对出现的,键值对。所以我们可以把他们看成是一个夫妻对的集合。
+            1、把所有的Key给集中起来
+            2、遍历Key的集合,获取每一个Key
+            3、根据Key 寻找Value
+    遍历步骤:
+        1、获取所有Key集合,使用keySet()方法实现。
+        2、遍历key集合,获取到每一个键,可以使用foreach
+        3、根据key寻找value,使用get(Object key)方法来实现
+
+    Map的遍历方式二:
+        1、获取所有键值对(Entry)对象的集合
+        2、遍历键值对对象的集合
+        3、根据键值对分别获取键和值
+    
+    
+     */
+    public static void main(String[] args) {
+        Map<String,Object> map=new HashMap<>();
+        map.put("x001","张三");
+        map.put("x002","李四");
+        map.put("x003","王五");
+        map.put("x004","赵六");
+
+        System.out.println("---------遍历Map集合:方式一-------------");
+        //1、获取所有Key集合,使用keySet()方法实现。
+        Set<String> set = map.keySet();
+        //2、遍历key集合,获取到每一个键,可以使用foreach
+        for (String key:set){
+            //3、根据key寻找value,使用get(Object key)方法来实现
+            Object value = map.get(key);
+            System.out.println("key:"+key+",value:"+value);
+        }
+        System.out.println("---------遍历Map集合:方式二-------------");
+        //1、获取所有键值对(Entry)对象的集合
+        Set<Map.Entry<String, Object>> entries = map.entrySet();
+        //2、遍历键值对对象的集合
+        for (Map.Entry<String, Object> me:entries){
+            //3、根据键值对分别获取键和值
+            String key = me.getKey();
+            Object value = me.getValue();
+            System.out.println("key:"+key+",value:"+value);
+        }
+    }
+}

+ 70 - 0
授课代码/c260731/src/course/Demo05.java

@@ -0,0 +1,70 @@
+package course;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo05
+ * @description HashMap
+ * @create 2026/7/31
+ */
+public class Demo05 {
+    /*
+        HashMap集合
+            HashMap集合是实现了Map接口的一种基于【哈希表结构】实现的集合。
+            HashMap集合依赖 hashCode方法和equals方法来保证 键Key的唯一。
+            所以如果自定义类型想要存入到HashMap的Key中,就一定要重写【hashCode方法和equals方法】
+        哈希值 :
+            哈希值是JDK根据对象的地址,或者字符串或者数字算出来的int类型的数值。
+            获取哈希值的方式就是Object类中的hashCode(),返回的就是哈希码值
+            哈希值的特点:
+                同一个对象多次调用hashCode()方法,返回的哈希值是相同的。
+                默认情况下,不同的对象的哈希值是不同的,重写hashCode()可以让我们实现不同对象的哈希值相同。
+                一般是在多个个对象的所有属性值完全相同时,hashCode()方法需要返回相同的哈希值。
+        哈希表结构是什么?
+            哈希表本质来讲,就可以理解为 数组+链表
+
+            上面是数组,每个元素都有对应的索引值
+            其实是一个默认长度为16的数组。
+            我们往里面添加的键值对的时候,会计算键的哈希值。计算的哈希值其实就是int整数
+            所以可能出现这样情况:
+
+            张三  --hash运算(hashCode)  --> 15
+            李四  --hash运算(hashCode)  --> 87
+            王五  --hash运算(hashCode)  --> 66
+            赵六  --hash运算(hashCode)  --> 20
+            wanjl  --hash运算(hashCode)  --> 15
+            哈么么  --hash运算(hashCode)  --> 70
+
+        HashMap--JDK1.7及之前
+            数组+链表 的哈希表结构
+            1、创建一个默认长度为16的,默认的负载因子0.75的数组,数组名table
+            2、根据元素的哈希值跟数组长度进行计算,计算出应该存入的位置。
+            3、判断当前的位置是否为null,如果是null就直接存入
+            4、如果位置不是null,表示有元素,那么就调用equals方法比较这两个元素的属性值,判断是不是同一个。
+            5、如果判断发现两个对象是同一个,就不存了。如果不是同一个则存入数组,老的元素挂在新元素的下边。
+
+            能让两个相同哈希值的对象以链表的方式挂到后面。
+            原因就只有一个:
+                虽然哈希值相同,但是equals比较不同。
+            风险和弊端:
+                如果出现越来越多的哈希值相同,但是equals比较为false,的元素。
+                就会导致链表过长,性能下降。
+        HashMap--JDK1.8之后
+            JAVA1.8之后,引入了 红黑树,1.8之后的HashMap有两种形态:
+            第1种:数组+链表--哈希表
+            第2种:是在哈希表满足了某些条件后,从数组+链表 转换为 数组+红黑树。保证性能不会降低。
+        简单来说,就是链表的节点数超过8个,就转为红黑树。
+
+            HashMap的数组默认长度是16
+            static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
+            默认的负载因子是0.75,当已经存入数组的元素超过长度的0.75,那么就对数组进行扩容
+            static final float DEFAULT_LOAD_FACTOR = 0.75f;
+            HashMap从数组+链表的结构转为数组+红黑树的结构的阈值,树化阈值是8,链表节点长度超过8就树化。
+            static final int TREEIFY_THRESHOLD = 8;
+            当节点长度小于6的时候,会从红黑树退化会链表
+            static final int UNTREEIFY_THRESHOLD = 6;
+            数组+链表转为红黑树的第2个条件:数组长度大于64
+            static final int MIN_TREEIFY_CAPACITY = 64;
+
+     */
+}

+ 199 - 5
课堂笔记/01-JavaSE基础-笔记/20260731-笔记.md

@@ -1,4 +1,4 @@
-# 20260731 课堂笔记 — LinkedList 多接口形态 / Iterator 迭代器 / Map集合入门
+# 20260731 课堂笔记 — LinkedList 多接口形态 / Iterator 迭代器 / Map集合入门·遍历·底层原理)
 
 - **日期**:2026-07-31
 - **项目**:`c260731`
@@ -13,8 +13,10 @@
 2. [Iterator 迭代器](#2-iterator-迭代器)
 3. [Collection 体系回顾:Iterable → Collection](#3-collection-体系回顾iterable--collection)
 4. [Map 集合(双列集合)与 HashMap 入门](#4-map-集合双列集合与-hashmap-入门)
-5. [随堂练习要点](#5-随堂练习要点)
-6. [拓展阅读](#6-拓展阅读)
+5. [Map 集合的遍历(keySet + get / entrySet)](#5-map-集合的遍历keyset--get--entryset)
+6. [HashMap 底层原理(哈希表结构)](#6-hashmap-底层原理哈希表结构)
+7. [随堂练习要点](#7-随堂练习要点)
+8. [拓展阅读](#8-拓展阅读)
 
 ---
 
@@ -235,9 +237,21 @@ HashMap<String,Object> map1 = new HashMap<>();  // 方式二:直接用实现
 
 ### Map 常用方法
 
+#### 基本使用
+
 | 方法 | 说明 |
 |------|------|
 | `V put(K key, V value)` | 向 Map 集合中添加元素(键值对) |
+| `boolean containsKey(Object key)` | 判断 Map 集合中是否包含指定的 key 键 |
+| `boolean containsValue(Object value)` | 判断 Map 集合中是否包含指定的 value 值 |
+| `void clear()` | 清空集合,移除所有的键值对元素 |
+| `boolean isEmpty()` | 判断集合是否为空 |
+| `int size()` | 返回集合中的有效元素个数 |
+
+#### 获取元素
+
+| 方法 | 说明 |
+|------|------|
 | `V get(Object key)` | 根据 Key 键获取 Value 值 |
 | `Set<K> keySet()` | 把当前 Map 集合中的所有 Key 组成一个 Set 集合(无序的单列集合) |
 | `Collection<V> values()` | 把所有的 Value 值组合成一个单列集合 |
@@ -289,7 +303,157 @@ public class Demo03 {
 
 ---
 
-## 5. 随堂练习要点
+## 5. Map 集合的遍历(keySet + get / entrySet)
+
+### 概念
+
+Map 存入的元素都是成对出现的(键值对),可以把它看成是「夫妻对」的集合。Map 本身**没有索引**,不能像 List 那样用 `for + get(i)` 直接遍历,需要借助以下两种方式:
+
+**方式一(keySet + get):间接遍历**
+1. 获取所有 Key 集合,使用 `keySet()` 方法实现
+2. 遍历 key 集合,获取到每一个键(可以使用 foreach)
+3. 根据 key 寻找 value,使用 `get(Object key)` 方法来实现
+
+**方式二(entrySet):直接遍历**
+1. 获取所有键值对(Entry)对象的集合,使用 `entrySet()` 方法
+2. 遍历键值对对象的集合
+3. 根据键值对分别获取键和值(`getKey()` / `getValue()`)
+
+### 代码示例
+
+```java
+// 来源:course/Demo04.java
+package course;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class Demo04 {
+    public static void main(String[] args) {
+        Map<String,Object> map=new HashMap<>();
+        map.put("x001","张三");
+        map.put("x002","李四");
+        map.put("x003","王五");
+        map.put("x004","赵六");
+
+        System.out.println("---------遍历Map集合:方式一-------------");
+        //1、获取所有Key集合,使用keySet()方法实现。
+        Set<String> set = map.keySet();
+        //2、遍历key集合,获取到每一个键,可以使用foreach
+        for (String key:set){
+            //3、根据key寻找value,使用get(Object key)方法来实现
+            Object value = map.get(key);
+            System.out.println("key:"+key+",value:"+value);
+        }
+        System.out.println("---------遍历Map集合:方式二-------------");
+        //1、获取所有键值对(Entry)对象的集合
+        Set<Map.Entry<String, Object>> entries = map.entrySet();
+        //2、遍历键值对对象的集合
+        for (Map.Entry<String, Object> me:entries){
+            //3、根据键值对分别获取键和值
+            String key = me.getKey();
+            Object value = me.getValue();
+            System.out.println("key:"+key+",value:"+value);
+        }
+    }
+}
+```
+
+### 关键理解
+
+- **方式一是「间接遍历」**:先拿 Key 集合,再用 `get(key)` 反查 Value,每次 `get()` 都是一次哈希查找
+- **方式二是「直接遍历」**:一次性拿到键值对 Entry 对象,`getKey()` / `getValue()` 直接取值,效率更高
+- `Map.Entry<K,V>` 是 Map 的**内部类型**,一个 Entry 就代表一个「键值对」
+- 遍历结果依然体现 HashMap 的**无序**特性(顺序 ≠ 添加顺序)
+
+---
+
+## 6. HashMap 底层原理(哈希表结构)
+
+### 概念
+
+`HashMap` 是实现了 Map 接口的一种基于**哈希表结构**实现的集合:
+
+- 哈希表本质来讲,可以理解为 **数组 + 链表**
+- HashMap 依赖 `hashCode` 方法和 `equals` 方法来保证**键 Key 的唯一**
+- 所以**自定义类型**如果想存入 HashMap 的 Key 中,就**一定要重写 `hashCode()` 和 `equals()` 方法**
+
+### 哈希值
+
+哈希值是 JDK 根据**对象的地址、字符串或数字**算出来的 `int` 类型的数值。获取方式:调用 Object 类中的 `hashCode()`,返回的就是哈希码值。
+
+哈希值的特点:
+1. **同一个对象**多次调用 `hashCode()`,返回的哈希值是**相同**的
+2. **默认情况下**,不同的对象哈希值是不同的;重写 `hashCode()` 可以让我们实现不同对象的哈希值相同
+3. 一般是在**多个对象的所有属性值完全相同时**,`hashCode()` 需要返回相同的哈希值
+
+### 哈希表结构演示
+
+```java
+// 来源:course/Demo05.java(注释部分)
+// 上面的数组是默认长度为 16 的数组,添加键值对时先计算键的哈希值(int 整数)
+张三  --hash运算(hashCode)  --> 15
+李四  --hash运算(hashCode)  --> 87
+王五  --hash运算(hashCode)  --> 66
+赵六  --hash运算(hashCode)  --> 20
+wanjl --hash运算(hashCode)  --> 15    // 与"张三"哈希值相同 → 挂在同一位置的链表上
+哈么么 --hash运算(hashCode)  --> 70
+```
+
+### JDK 1.7 及之前:数组 + 链表
+
+存入流程:
+1. 创建**默认长度为 16**、**默认负载因子 0.75** 的数组,数组名 `table`
+2. 根据元素的哈希值跟数组长度进行计算,计算出应该存入的位置
+3. 判断当前位置是否为 `null`,是 `null` 就直接存入
+4. 如果位置不是 `null`(已有元素),就调用 `equals` 方法比较两个元素的属性值,判断是不是同一个
+5. 如果是同一个就不存了;**不是同一个则存入**,老的元素挂在新元素的下边(形成链表)
+
+> 能让两个相同哈希值的对象以链表的方式挂到后面,原因只有一个:**哈希值相同,但 equals 比较不同**。
+
+**风险和弊端**:如果出现越来越多哈希值相同、但 `equals` 比较为 `false` 的元素,就会导致**链表过长,性能下降**。
+
+### JDK 1.8 之后:数组 + 链表 / 红黑树
+
+Java 1.8 之后引入了**红黑树**,1.8 之后的 HashMap 有两种形态:
+
+- **第 1 种**:数组 + 链表(哈希表)
+- **第 2 种**:在哈希表满足了某些条件后,从「数组 + 链表」转换为「数组 + 红黑树」,保证性能不会降低
+
+简单来说:**链表的节点数超过 8 个,就转为红黑树**。
+
+### HashMap 关键常量
+
+| 常量 | 值 | 说明 |
+|------|-----|------|
+| `DEFAULT_INITIAL_CAPACITY` | `16`(`1 << 4`) | 数组默认长度 |
+| `DEFAULT_LOAD_FACTOR` | `0.75f` | 默认负载因子,已存入元素超过数组长度 × 0.75 就对数组扩容 |
+| `TREEIFY_THRESHOLD` | `8` | **树化阈值**:链表节点长度超过 8 就转为红黑树 |
+| `UNTREEIFY_THRESHOLD` | `6` | 当节点长度小于 6 时,从红黑树退化回链表 |
+| `MIN_TREEIFY_CAPACITY` | `64` | 数组 + 链表转红黑树的**第 2 个条件**:数组长度必须大于 64 |
+
+### 代码示例
+
+```java
+// 来源:course/Demo05.java(本类为理论注释讲解,无 main 方法)
+package course;
+
+public class Demo05 {
+    /*
+        HashMap集合
+            HashMap集合是实现了Map接口的一种基于【哈希表结构】实现的集合。
+            HashMap集合依赖 hashCode方法和equals方法来保证 键Key的唯一。
+            所以如果自定义类型想要存入到HashMap的Key中,就一定要重写【hashCode方法和equals方法】
+        ...
+        (核心内容见上方各小节)
+     */
+}
+```
+
+---
+
+## 7. 随堂练习要点
 
 ### 练习一:LinkedList 多接口引用
 
@@ -328,9 +492,34 @@ public class Demo03 {
 2. 为什么 HashMap 打印时顺序和添加顺序不一致?—— 底层根据键的 hashCode 哈希决定存储位置
 3. 为什么 `keySet()` 返回 Set?—— 键不可重复,正好符合 Set 的不可重复特性
 
+### 练习四:遍历 Map 集合(两种方式)
+
+**核心步骤**:
+1. 创建 `HashMap<String,Object>`,用 `put()` 添加 4 组键值对
+2. **方式一**:`keySet()` 获取所有键 → foreach 遍历键 → `get(key)` 获取值
+3. **方式二**:`entrySet()` 获取所有 Entry → foreach 遍历 → `getKey()` / `getValue()` 获取键值
+4. 对比两种方式的遍历输出
+
+**思考**:
+1. keySet 方式为什么比 entrySet 方式多一次查找?—— keySet 拿到 key 后还要用 `get(key)` 反查 value,entrySet 直接同时拿到键和值
+2. `Map.Entry<String,Object>` 中的泛型怎么理解?—— 键是 String 类型,值是 Object 类型,Entry 就是这个键值对的类型
+3. foreach 遍历 `Set<Map.Entry<...>>` 的底层是什么?—— 编译器翻译成迭代器遍历
+
+### 练习五:HashMap 底层原理理解
+
+**核心步骤**:
+1. 阅读 Demo05 的注释,画出「数组 + 链表」的哈希表结构图
+2. 手写一个自定义类,重写 `hashCode()` 和 `equals()`,验证它能作为 HashMap 的 Key
+3. 说出 JDK1.7 和 JDK1.8 的 HashMap 结构差异
+
+**思考**:
+1. 为什么 HashMap 的 Key 要求重写 `hashCode()` 和 `equals()`?—— 哈希表要计算 Key 的存储位置(hashCode),并判断两个 Key 是否相同(equals),二者缺一不可
+2. 为什么 JDK1.8 要引入红黑树?—— 防止哈希冲突导致链表过长、查询退化为 O(n),红黑树保证 O(log n) 的查询效率
+3. 负载因子 0.75 的含义?—— 当已存元素个数超过容量 × 0.75 时触发扩容(默认 16 → 扩容后约 32)
+
 ---
 
-## 6. 拓展阅读
+## 8. 拓展阅读
 
 ### 官方文档
 
@@ -341,11 +530,15 @@ public class Demo03 {
 - [Deque (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Deque.html)
 - [Map 接口 (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Map.html)
 - [HashMap (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/HashMap.html)
+- [Map.Entry (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Map.Entry.html)
+- [Object.hashCode() (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#hashCode())
+- [红黑树 Red-Black Tree(Wikipedia)](https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91)
 
 ### 推荐阅读
 
 - 《Java 核心技术 卷 I》第 9 章 集合 —— 迭代器与 foreach 的关系、Map 集合
 - 《Effective Java》第 3 版 第 58 条:优先使用 foreach 循环而非传统 for 循环
+- 《Java 编程思想》第 17 章 容器深入研究 —— 散列与哈希码
 
 ### 相关知识点
 
@@ -355,3 +548,4 @@ public class Demo03 {
 | LinkedList 双链表理论(0730) | Iterator 迭代器 | 增强 for / forEach 方法 |
 | 泛型与集合体系(0729) | Iterable → Collection 继承体系 | Set 集合与 Map 迭代 |
 | Collection 单列集合体系 | Map 集合 / HashMap 入门 | Map 遍历(entrySet)、HashMap 底层哈希表 |
+| equals/hashCode 重写(0728) | HashMap 底层原理(数组+链表/红黑树) | HashMap 扩容机制、哈希冲突优化 |