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

docs: 更新20260803课堂笔记及README,同步代码变更——新增可变参数Varargs知识点(Demo03:add(int... a)参数个数可变、本质即数组、可变参数置末)及随堂练习参考解答(exericse/exericse02:EmployeeSystem员工管理、compareTo薪资降序+工号、equals/hashCode重写、匿名内部类按姓名排序)

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

+ 2 - 2
README.md

@@ -37,7 +37,7 @@
 | 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集合(入门/遍历/底层原理)+ 二叉树(二叉搜索树/平衡二叉树/红黑树)](./课堂笔记/01-JavaSE基础-笔记/20260731-笔记.md) |
-| 2026-08-03 | [比较器排序:Comparable 自然排序 / Comparator 比较器排序 + 集合工具类 Collections + 20260731 课后作业解析(Map 操作与遍历、异常处理综合、匿名内部类 Comparator 排序)](./课堂笔记/01-JavaSE基础-笔记/20260803-笔记.md) |
+| 2026-08-03 | [比较器排序:Comparable 自然排序 / Comparator 比较器排序 + 集合工具类 Collections + 可变参数 Varargs + 20260731 课后作业解析(Map 操作与遍历、异常处理综合、匿名内部类 Comparator 排序)](./课堂笔记/01-JavaSE基础-笔记/20260803-笔记.md) |
 
 ## 二、授课代码
 
@@ -61,7 +61,7 @@
 | 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/containsKey)、遍历(keySet+get / entrySet)、HashMap底层原理(数组+链表/红黑树、hashCode/equals、5个关键常量)+ 二叉树(二叉搜索树/平衡二叉树AVL/红黑树规则与旋转)+ 随堂练习参考解答(自定义Key/词频统计) | `c260731` | [`course`](./授课代码/c260731/src/course/) / [`exericse/exericse01`](./授课代码/c260731/src/exericse/exericse01/) / [`exericse/exericse02`](./授课代码/c260731/src/exericse/exericse02/) |
-| 2026-08-03 | 比较器排序:TreeSet/TreeMap 有序集合、Comparable 自然排序(course/Student implements Comparable、compareTo 按年龄二次比较姓名)、Comparator 比较器排序(course/Demo01:TreeSet 构造传入匿名内部类 Comparator);集合工具类 Collections(course/Demo02:sort/sort+Comparator/reverse/binarySearch/max/min/unmodifiableList/shuffle/fill/swap/rotate/replaceAll + List.of 快速创建集合);20260731 课后作业解析:Map 集合基本操作与遍历(homework0731/p2_map)、异常处理综合(homework0731/p4_exception:自定义异常 InvalidScoreException + 多 catch 块 + 输入校验)、匿名内部类 Comparator 排序(homework0731/p5_sort:Collections.sort 按年龄升序/成绩降序 Double.compare) | `c260803` | [`course`](./授课代码/c260803/src/course/) / [`homework0731/p2_map`](./授课代码/c260803/src/homework0731/p2_map/) / [`homework0731/p4_exception`](./授课代码/c260803/src/homework0731/p4_exception/) / [`homework0731/p5_sort`](./授课代码/c260803/src/homework0731/p5_sort/) |
+| 2026-08-03 | 比较器排序:TreeSet/TreeMap 有序集合、Comparable 自然排序(course/Student implements Comparable、compareTo 按年龄二次比较姓名)、Comparator 比较器排序(course/Demo01:TreeSet 构造传入匿名内部类 Comparator);集合工具类 Collections(course/Demo02:sort/sort+Comparator/reverse/binarySearch/max/min/unmodifiableList/shuffle/fill/swap/rotate/replaceAll + List.of 快速创建集合);可变参数 Varargs(course/Demo03:add(int... a) 参数个数可变、本质即数组、可变参数必须放最后);20260731 课后作业解析:Map 集合基本操作与遍历(homework0731/p2_map)、异常处理综合(homework0731/p4_exception:自定义异常 InvalidScoreException + 多 catch 块 + 输入校验)、匿名内部类 Comparator 排序(homework0731/p5_sort:Collections.sort 按年龄升序/成绩降序 Double.compare);随堂练习参考解答(exericse/exericse02:EmployeeSystem 员工管理,compareTo 薪资降序+工号、equals/hashCode 重写、匿名内部类按姓名排序) | `c260803` | [`course`](./授课代码/c260803/src/course/) / [`exericse/exericse02`](./授课代码/c260803/src/exericse/exericse02/) / [`homework0731/p2_map`](./授课代码/c260803/src/homework0731/p2_map/) / [`homework0731/p4_exception`](./授课代码/c260803/src/homework0731/p4_exception/) / [`homework0731/p5_sort`](./授课代码/c260803/src/homework0731/p5_sort/) |
 
 ## 三、课堂练习题
 

+ 63 - 0
授课代码/c260803/src/course/Demo03.java

@@ -0,0 +1,63 @@
+package course;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Demo03
+ * @description 可变参数
+ * @create 2026/8/3
+ */
+public class Demo03 {
+    /*
+        形参:全称形式参数,是在方法声明的时候定义的参数
+        public void method(形参类型 形参名){
+
+        }
+
+        实参:全称实际参数,是在调用方法的时候传入的实际参数值
+        setName("张三")  张三就是实际参数
+        可变参数也叫参数个数可变,作为方法的形参出现,也就是方法形参的个数是可以改变的。
+
+        以前我们尝试过。比如计算两个整数相加、三个整数相减、四个整数相加等等,使用的时候方法的重载。方便用户使用,但是并不方便我们自己定义。
+        我们还是需要有几个参数,就要定义对应的方法。
+        现在有了可变参数,我们就可以使用可变参数了。
+        格式:
+        访问权限修饰符 返回值类型 方法名(形参类型... 参数名){
+
+        }
+        注意:
+            可变参数其实就是一个数组
+            如果一个方法有多个参数,包含可变参数,那么可变参数要放在最后
+
+
+     */
+    public int add(int a,int b){
+        return a+b;
+    }
+
+    /**
+     * 可以实现多个整数累加和
+     * @param a 就是一个可变参数
+     * @return
+     */
+    public int add(int... a){   //实际上等价于 dd(int[] a)
+        int sum=0;
+        for (int n:a){
+            sum+=n;
+        }
+        return sum;
+    }
+
+
+    public static void main(String[] args) {
+        int sum = new Demo03().add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+        //上面的一行,和下面的两行。效果也是一样的。
+        int[] arr={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+        int sum1 = new Demo03().add(arr);
+
+
+        System.out.println(sum);
+    }
+
+
+}

+ 89 - 0
授课代码/c260803/src/exericse/exericse02/Employee.java

@@ -0,0 +1,89 @@
+package exericse.exericse02;
+
+import java.util.Objects;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title Employee
+ * @description
+ * @create 2026/8/3
+ */
+public class Employee implements Comparable<Employee> {
+    private String id;      // 工号
+    private String name;    // 姓名
+    private double salary;  // 薪资
+    private String dept;    // 部门
+
+    public Employee(String id, String name, double salary, String dept) {
+        this.id = id;
+        this.name = name;
+        this.salary = salary;
+        this.dept = dept;
+    }
+
+    // TODO: 补全 getter / setter / toString 方法
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public double getSalary() {
+        return salary;
+    }
+
+    public void setSalary(double salary) {
+        this.salary = salary;
+    }
+
+    public String getDept() {
+        return dept;
+    }
+
+    public void setDept(String dept) {
+        this.dept = dept;
+    }
+
+    // TODO: 重写 compareTo —— 按薪资降序,薪资相同再按工号
+    @Override
+    public int compareTo(Employee o) {
+        // 提示:Double.compare(o.getSalary(), this.salary)  // 降序
+        //       若返回 0,再比较工号:this.id.compareTo(o.getId())
+        int result= Double.compare(o.getSalary(), this.salary);
+        return result==0?this.id.compareTo(o.getId()):result;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || getClass() != o.getClass()) return false;
+        Employee employee = (Employee) o;
+        return Double.compare(salary, employee.salary) == 0 && Objects.equals(id, employee.id) && Objects.equals(name, employee.name) && Objects.equals(dept, employee.dept);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, name, salary, dept);
+    }
+
+    @Override
+    public String toString() {
+        return "Employee{" +
+                "id='" + id + '\'' +
+                ", name='" + name + '\'' +
+                ", salary=" + salary +
+                ", dept='" + dept + '\'' +
+                '}';
+    }
+}

+ 66 - 0
授课代码/c260803/src/exericse/exericse02/EmployeeSystem.java

@@ -0,0 +1,66 @@
+package exericse.exericse02;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+
+/**
+ * @author WanJl
+ * @version 1.0
+ * @title EmployeeSystem
+ * @description
+ * @create 2026/8/3
+ */
+public class EmployeeSystem {
+    public static void main(String[] args) {
+        // 1. 创建 TreeSet<Employee>(自然排序)
+        //    添加 5 名员工(其中两名工号相同,测试去重):
+        //    E001-张三-12000-技术部 / E002-李四-15000-市场部
+        //    E003-王五-15000-技术部 / E004-赵六-9000-财务部
+        //    E005-刘七-12000-市场部
+        TreeSet<Employee> treeSet=new TreeSet<>();
+        treeSet.add(new Employee("E001","张三",12000,"技术部"));
+        treeSet.add(new Employee("E002","李四",15000,"市场部"));
+        treeSet.add(new Employee("E003","王五",15000,"技术部"));
+        treeSet.add(new Employee("E004","赵六",9000,"财务部"));
+        treeSet.add(new Employee("E005","刘七",12000,"市场部"));
+
+        // 2. 迭代器遍历输出 → 观察:按薪资降序,薪资相同按工号;工号重复的自动去重
+        //    输出格式:"E001-张三-12000.0-技术部"
+        Iterator<Employee> iterator = treeSet.iterator();
+        while (iterator.hasNext()){
+            Employee employee = iterator.next();
+            System.out.println(employee.getId()+"-"+employee.getName()+"-"+employee.getSalary()+"-"+employee.getDept());
+        }
+
+
+        // 3. 临时需求:通讯录按姓名排序 —— 创建 TreeSet<Employee> 传入按姓名排序的 Comparator
+        //    匿名内部类:o1.getName().compareTo(o2.getName())
+        //    迭代器遍历输出
+
+        treeSet=new TreeSet<>(new Comparator<Employee>() {
+            @Override
+            public int compare(Employee o1, Employee o2) {
+                return o1.getName().compareTo(o2.getName());
+            }
+        });
+        treeSet.add(new Employee("E001","张三",12000,"技术部"));
+        treeSet.add(new Employee("E002","李四",15000,"市场部"));
+        treeSet.add(new Employee("E003","王五",15000,"技术部"));
+        treeSet.add(new Employee("E004","赵六",9000,"财务部"));
+        treeSet.add(new Employee("E005","刘七",12000,"市场部"));
+
+        iterator = treeSet.iterator();
+        while (iterator.hasNext()){
+            Employee employee = iterator.next();
+            System.out.println(employee.getId()+"-"+employee.getName()+"-"+employee.getSalary()+"-"+employee.getDept());
+        }
+
+        // 4. 思考:E001-张三(12000) 和 E005-刘七(12000) 薪资相同,为何都能存入?
+        //    —— compareTo 在薪资相同后继续比较工号,返回值不为 0
+
+
+
+    }
+}

+ 167 - 12
课堂笔记/01-JavaSE基础-笔记/20260803-笔记.md

@@ -1,8 +1,8 @@
-# 20260803 课堂笔记 — 比较器排序(Comparable 自然排序 / Comparator 比较器排序)+ 集合工具类 Collections + 20260731 课后作业解析
+# 20260803 课堂笔记 — 比较器排序(Comparable 自然排序 / Comparator 比较器排序)+ 集合工具类 Collections + 可变参数 Varargs + 20260731 课后作业解析
 
 - **日期**:2026-08-03
 - **项目**:`c260803`
-- **包路径**:`course` / `homework0731`
+- **包路径**:`course` / `exericse` / `homework0731`
 - **作者**:WanJL
 
 ---
@@ -14,11 +14,12 @@
 3. [比较器排序 Comparator(临时自定义排序)](#3-比较器排序-comparator临时自定义排序)
 4. [返回值规则与 compareTo/equals 一致性的官方推荐](#4-返回值规则与-comparetoequals-一致性的官方推荐)
 5. [集合工具类 Collections](#5-集合工具类-collections)
-6. [20260731 课后作业解析:Map 集合基本操作与遍历](#6-20260731-课后作业解析map-集合基本操作与遍历)
-7. [20260731 课后作业解析:异常处理综合(自定义异常)](#7-20260731-课后作业解析异常处理综合自定义异常)
-8. [20260731 课后作业解析:匿名内部类 Comparator 排序](#8-20260731-课后作业解析匿名内部类-comparator-排序)
-9. [随堂练习要点](#9-随堂练习要点)
-10. [拓展阅读](#10-拓展阅读)
+6. [可变参数 Varargs(参数个数可变)](#6-可变参数-varargs参数个数可变)
+7. [20260731 课后作业解析:Map 集合基本操作与遍历](#7-20260731-课后作业解析map-集合基本操作与遍历)
+8. [20260731 课后作业解析:异常处理综合(自定义异常)](#8-20260731-课后作业解析异常处理综合自定义异常)
+9. [20260731 课后作业解析:匿名内部类 Comparator 排序](#9-20260731-课后作业解析匿名内部类-comparator-排序)
+10. [随堂练习要点](#10-随堂练习要点)
+11. [拓展阅读](#11-拓展阅读)
 
 ---
 
@@ -291,7 +292,81 @@ public class Demo02 {
 
 ---
 
-## 6. 20260731 课后作业解析:Map 集合基本操作与遍历
+## 6. 可变参数 Varargs(参数个数可变)
+
+### 概念
+
+**可变参数**也叫**参数个数可变**,作为方法的**形参**出现——也就是说**方法形参的个数是可以改变的**。
+
+先回顾两个基础概念:
+- **形参**(形式参数):在**方法声明**的时候定义的参数,如 `public void method(int 形参名)`
+- **实参**(实际参数):在**调用方法**的时候传入的实际参数值,如 `setName("张三")`,其中的 `"张三"` 就是实际参数
+
+**为什么要用可变参数?**
+之前计算"多个整数相加",有多少个参数就要写多少个**方法重载**(`add(int a, int b)` / `add(int a, int b, int c)` / `add(int a, int b, int c, int d)`...)。这样**方便用户使用,但不利于我们自己定义**——写多少个重载都覆盖不完所有情况。有了可变参数,一个方法就能接收任意个数参数。
+
+**格式**:
+```java
+访问权限修饰符 返回值类型 方法名(形参类型... 参数名){
+    // 方法体
+}
+```
+
+### 代码示例
+
+```java
+// 来源:course/Demo03.java
+package course;
+
+public class Demo03 {
+    // 传统写法:几个参数就要重载几个方法
+    public int add(int a, int b) {
+        return a + b;
+    }
+
+    /**
+     * 可变参数:可以实现多个整数累加和
+     * @param a 就是一个可变参数(实际上等价于 int[] a)
+     */
+    public int add(int... a) {   // 本质上等价于 add(int[] a)
+        int sum = 0;
+        for (int n : a) {
+            sum += n;
+        }
+        return sum;
+    }
+
+    public static void main(String[] args) {
+        // 直接传入任意多个整数
+        int sum = new Demo03().add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+
+        // 上面这一行,和下面这两行效果一样——可变参数本质就是数组
+        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+        int sum1 = new Demo03().add(arr);
+
+        System.out.println(sum);
+    }
+}
+```
+
+### 注意事项
+
+| 注意点 | 说明 |
+|--------|------|
+| **可变参数本质就是一个数组** | `int... a` 与 `int[] a` 等价,方法内用 foreach 遍历即可 |
+| **可变参数必须放在参数列表最后** | 一个方法有多个参数时,可变参数不能写在固定参数前面 |
+| **只能有一个可变参数** | 一个方法最多只能有一个可变参数 |
+| 调用方式灵活 | 既可以传 0 个、1 个、多个参数,也可以直接传一个数组 |
+
+### 关键理解
+
+1. **可变参数 = 数组的语法糖**:`int... a` 在方法内部就是一个 `int[] a`,所以遍历方式和数组完全一致。
+2. **与重载的取舍**:参数个数不固定时用可变参数更简洁;参数个数固定、类型不同时用重载更清晰。
+3. **与其他参数共存**:如果方法既有固定参数又有可变参数,可变参数必须写在最后,如 `public void method(String name, int... scores)`。
+
+---
+
+## 7. 20260731 课后作业解析:Map 集合基本操作与遍历
 
 ### 作业要求回顾
 
@@ -364,7 +439,7 @@ public class MapDemo {
 
 ---
 
-## 7. 20260731 课后作业解析:异常处理综合(自定义异常)
+## 8. 20260731 课后作业解析:异常处理综合(自定义异常)
 
 ### 作业要求回顾
 
@@ -439,7 +514,7 @@ public class ScoreStatisticsDemo {
 
 ---
 
-## 8. 20260731 课后作业解析:匿名内部类 Comparator 排序
+## 9. 20260731 课后作业解析:匿名内部类 Comparator 排序
 
 ### 作业要求回顾
 
@@ -521,7 +596,7 @@ public class Student {
 
 ---
 
-## 9. 随堂练习要点
+## 10. 随堂练习要点
 
 ### 练习一:自然排序(Comparable)与比较器排序(Comparator)对比
 
@@ -584,9 +659,87 @@ public class Student {
 2. `binarySearch` 查找前为什么要先排序?—— 二分查找基于有序序列,未排序结果不可靠
 3. `List.of()` 返回的集合为什么不能 `add/remove`?—— 返回的是不可变集合,直接修改抛 `UnsupportedOperationException`,需用 `new ArrayList<>(...)` 包装
 
+### 练习六:可变参数(Varargs)—— 任意个数整数求和
+
+**核心步骤**:
+1. 定义一个方法 `add(int... a)`,方法内用 foreach 累加求和
+2. 分别调用:`add(1, 2)`、`add(1, 2, 3)`、`add(1, 2, 3, 4, 5)`,体会"一个方法接收任意个数参数"
+3. 用数组调用:`int[] arr = {...}; add(arr)`,验证"可变参数本质就是数组"
+4. 定义带固定参数的方法:`method(String name, int... scores)`,验证可变参数必须放在最后
+
+**思考**:
+1. `int... a` 和 `int[] a` 有什么关系?—— 本质相同,`int... a` 是 `int[] a` 的语法糖
+2. 为什么有了可变参数还要方法重载?—— 参数**个数**不确定时用可变参数;参数**个数固定、类型不同**时重载更清晰
+3. 如果方法同时有固定参数和可变参数,顺序有什么要求?—— 可变参数必须写在**参数列表最后**,否则编译报错
+
+### 随堂练习参考解答(已提供代码)
+
+对应今日课堂练习的参考解答已写入授课代码:
+
+| 练习 | 参考代码路径 |
+|------|-------------|
+| 进阶 2:员工信息管理系统(Employee 实现 Comparable + equals/hashCode 一致性 + 匿名内部类 Comparator 按姓名排序) | [`exericse/exericse02/Employee.java`](./../授课代码/c260803/src/exericse/exericse02/Employee.java) + [`EmployeeSystem.java`](./../授课代码/c260803/src/exericse/exericse02/EmployeeSystem.java) |
+
+**Employee 参考解答要点**:
+
+```java
+// 来源:exericse/exericse02/Employee.java
+// 自然排序:按薪资降序,薪资相同再按工号
+@Override
+public int compareTo(Employee o) {
+    int result = Double.compare(o.getSalary(), this.salary);  // 薪资降序
+    return result == 0 ? this.id.compareTo(o.getId()) : result;
+}
+
+// equals / hashCode:基于全部属性(salary + id + name + dept)
+@Override
+public boolean equals(Object o) {
+    if (o == null || getClass() != o.getClass()) return false;
+    Employee employee = (Employee) o;
+    return Double.compare(salary, employee.salary) == 0
+            && Objects.equals(id, employee.id)
+            && Objects.equals(name, employee.name)
+            && Objects.equals(dept, employee.dept);
+}
+
+@Override
+public int hashCode() {
+    return Objects.hash(id, name, salary, dept);
+}
+```
+
+**EmployeeSystem 参考解答要点**:
+
+```java
+// 来源:exericse/exericse02/EmployeeSystem.java
+// 1. 默认自然排序:薪资降序 → 薪资相同按工号;工号相同的自动去重
+TreeSet<Employee> treeSet = new TreeSet<>();
+treeSet.add(new Employee("E001", "张三", 12000, "技术部"));
+// ... 共添加 5 名员工
+
+// 迭代器遍历输出
+Iterator<Employee> iterator = treeSet.iterator();
+while (iterator.hasNext()) {
+    Employee employee = iterator.next();
+    System.out.println(employee.getId() + "-" + employee.getName() + "-" + employee.getSalary() + "-" + employee.getDept());
+}
+
+// 2. 临时需求:通讯录按姓名排序 → 重新创建 TreeSet 传入按姓名排序的匿名 Comparator
+treeSet = new TreeSet<>(new Comparator<Employee>() {
+    @Override
+    public int compare(Employee o1, Employee o2) {
+        return o1.getName().compareTo(o2.getName());
+    }
+});
+```
+
+**原理思考**:
+1. `E001-张三(12000)` 和 `E005-刘七(12000)` 薪资相同却能都存入?—— compareTo 薪资相同后继续比较工号(E001 ≠ E005),返回值不为 0,不视为重复
+2. 注意:参考解答的 `equals` 基于**全部属性**(薪资+工号+姓名+部门),而 `compareTo` 只按**薪资+工号**判定——若两名员工薪资工号相同但姓名不同,会出现 `compareTo == 0` 但 `equals == false`。这与官方推荐(compareTo == 0 时 equals 返回 true)略有出入,实际开发中应尽量让两者判定口径保持一致。
+
 ---
 
-## 10. 拓展阅读
+## 11. 拓展阅读
 
 ### 官方文档
 
@@ -596,6 +749,7 @@ public class Student {
 - [TreeMap (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/TreeMap.html)
 - [Collections 工具类 (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Collections.html)
 - [List.of() (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/List.html#of())
+- [可变参数 Varargs(Oracle 教程)](https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html#varargs)
 - [RuntimeException (JDK 17)](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/RuntimeException.html)
 
 ### 推荐阅读
@@ -614,3 +768,4 @@ public class Student {
 | 异常处理(0728) | 自定义异常 + 多 catch 块 | 异常链、try-with-resources |
 | Arrays 工具类(0716) | Collections 集合工具类 | Stream API、Java 8 新特性 |
 | Comparator 比较器排序(本节 3) | Collections.sort(list, comparator) | 函数式接口 & Lambda 简化比较器 |
+| 数组与方法参数(0717) | 可变参数 Varargs | 不定长参数 & 命令行参数、Stream 收集 |