|
|
@@ -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 收集 |
|