|
@@ -0,0 +1,489 @@
|
|
|
|
|
+# 2026年8月3日 课后作业 — 比较器排序 / Collections 工具类 / 可变参数 / Lambda 表达式
|
|
|
|
|
+
|
|
|
|
|
+> **说明**:本次作业围绕今日授课核心内容——**比较器排序(Comparable 自然排序 / Comparator 比较器排序)**、**集合工具类 Collections**、**可变参数 Varargs** 与 **Lambda 表达式(函数式接口)** 展开,涵盖 compareTo/compare 返回值规则、二次比较(多字段排序)、Collections.sort + 匿名内部类、Double.compare 降序技巧、可变参数本质与置末规则、Lambda 标准格式与三条省略规则、compareTo 与 equals/hashCode 一致性等知识点,并附 1 道简答题(Lambda vs 匿名内部类)。
|
|
|
|
|
+>
|
|
|
|
|
+> 题目分为 **⭐ 基础(必做)**:作业 1~3;**⭐⭐ 进阶(必做)**:作业 4~5;**简答题(必做)**。请新建 Java 项目,编写并运行代码,将运行结果截图提交。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 📌 本次作业重要说明
|
|
|
|
|
+
|
|
|
|
|
+### 命名要求
|
|
|
|
|
+
|
|
|
|
|
+| 项目 | 要求 |
|
|
|
|
|
+|------|------|
|
|
|
|
|
+| **包名** | **必须按题目指定的包名创建**(全小写) |
|
|
|
|
|
+| **类名** | 自由命名,但需**见名知意** |
|
|
|
|
|
+| **测试类** | 建议命名为 `TestXxx` 或 `XxxTest` |
|
|
|
|
|
+| **文件名** | 必须与类名一致 |
|
|
|
|
|
+
|
|
|
|
|
+### 提交目录结构示例
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+提交\
|
|
|
|
|
+└─ 张三\
|
|
|
|
|
+ ├─ p1_comparable\ ← 第 1 题的包(Comparable 自然排序)
|
|
|
|
|
+ │ ├─ Student.java
|
|
|
|
|
+ │ └─ ScoreRankingTest.java
|
|
|
|
|
+ ├─ p2_comparator\ ← 第 2 题的包(Comparator + Collections 工具类)
|
|
|
|
|
+ │ ├─ Product.java
|
|
|
|
|
+ │ └─ ProductSortDemo.java
|
|
|
|
|
+ ├─ p3_varargs\ ← 第 3 题的包(可变参数)
|
|
|
|
|
+ │ ├─ Calculator.java
|
|
|
|
|
+ │ └─ ScoreCalculator.java
|
|
|
|
|
+ ├─ p4_lambda\ ← 第 4 题的包(Lambda 表达式)
|
|
|
|
|
+ │ ├─ Addable.java
|
|
|
|
|
+ │ ├─ Flyable.java
|
|
|
|
|
+ │ └─ LambdaDemo.java
|
|
|
|
|
+ └─ p5_employee\ ← 第 5 题的包(综合应用)
|
|
|
|
|
+ ├─ Employee.java
|
|
|
|
|
+ └─ EmployeeSystem.java
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+> ⚠ **注意**:
|
|
|
|
|
+> 1. 包名必须严格按题目要求书写(全小写),目录结构必须与包结构一致
|
|
|
|
|
+> 2. 每个 Java 文件头部需包含 `@author`、`@title`、`@create` 文档注释
|
|
|
|
|
+> 3. 简答题(Lambda 与匿名内部类)请写在 Word / TXT 文档中,与代码一起提交
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# 第一部分:基础题(⭐ 必做)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 作业 1:Comparable 自然排序 — 学生成绩排行榜
|
|
|
|
|
+
|
|
|
|
|
+**包名**:`p1_comparable`
|
|
|
|
|
+
|
|
|
|
|
+**知识点**:`Comparable<T>` 接口、`compareTo(T o)` 重写、返回值规则(负数存左 / 0 重复不存 / 正数存右)、**二次比较**、`TreeSet` 自动排序 + 去重
|
|
|
|
|
+
|
|
|
|
|
+**场景描述**:编写学生成绩排行榜。`Student` 类实现 `Comparable`(**按成绩降序**,成绩相同再按姓名),存入 `TreeSet` 后**自动排序**并**自动去重**。
|
|
|
|
|
+
|
|
|
|
|
+**题目要求**:
|
|
|
|
|
+
|
|
|
|
|
+1. 定义 `Student` 类(`name`、`age`、`score`),**实现 `Comparable<Student>`**,重写 `compareTo`:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+// Student.java
|
|
|
|
|
+public class Student implements Comparable<Student> {
|
|
|
|
|
+ private String name;
|
|
|
|
|
+ private int age;
|
|
|
|
|
+ private double score;
|
|
|
|
|
+
|
|
|
|
|
+ public Student(String name, int age, double score) {
|
|
|
|
|
+ this.name = name;
|
|
|
|
|
+ this.age = age;
|
|
|
|
|
+ this.score = score;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 补全 getter / setter / toString 方法
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 重写 compareTo —— 按成绩降序,成绩相同再按姓名
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int compareTo(Student o) {
|
|
|
|
|
+ // 提示:int result = Double.compare(o.getScore(), this.score); // 降序
|
|
|
|
|
+ // return result == 0 ? this.name.compareTo(o.getName()) : result;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. 编写测试类 `ScoreRankingTest`:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+import java.util.TreeSet;
|
|
|
|
|
+
|
|
|
|
|
+public class ScoreRankingTest {
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
|
+ // 1. 创建 TreeSet<Student>(不传 Comparator → 使用自然排序)
|
|
|
|
|
+ // 2. 添加 5 名学生:
|
|
|
|
|
+ // 张三 18 90 / 李四 19 85 / 王五 20 95 / 赵六 18 90 / 孙七 21 88
|
|
|
|
|
+ // 注意:张三和赵六【成绩相同】→ 应触发姓名二次比较,两人都能存入
|
|
|
|
|
+ // 3. foreach 遍历输出,观察:成绩降序、同分按姓名排序
|
|
|
|
|
+ // 4. 再添加一名"刘八 22 90"(与张三成绩相同),观察去重行为
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**预期输出**:
|
|
|
|
|
+```
|
|
|
|
|
+========== 学生成绩排行榜 ==========
|
|
|
|
|
+王五 20 95.0
|
|
|
|
|
+张三 18 90.0
|
|
|
|
|
+赵六 18 90.0 ← 与张三同分 → 按姓名二次比较(张 < 赵),都能存入
|
|
|
|
|
+孙七 21 88.0
|
|
|
|
|
+李四 19 85.0
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**思考题**(选做,不要求提交代码):
|
|
|
|
|
+1. 返回值负数 / 0 / 正数分别代表什么?存入 TreeSet 时如何处理?
|
|
|
|
|
+2. 为什么张三和赵六成绩相同(90)却都能存入?—— `compareTo` 做了二次比较(姓名),返回值不为 0
|
|
|
|
|
+3. 如果 `compareTo` 只按成绩比较,会出现什么现象?(提示:同分视为重复,后一个不存)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 作业 2:Comparator 比较器排序 + Collections 工具类 — 商品价格排序
|
|
|
|
|
+
|
|
|
|
|
+**包名**:`p2_comparator`
|
|
|
|
|
+
|
|
|
|
|
+**知识点**:`Collections.sort(list, comparator)`、**匿名内部类**实现 Comparator、`Double.compare`、降序技巧(交换参数)、`Collections.max/min/binarySearch`
|
|
|
|
|
+
|
|
|
|
|
+**场景描述**:`Product` 类(名称 + 价格 + 库存)**不实现** `Comparable`。用 **Collections.sort + 匿名内部类 Comparator** 对商品进行多种临时排序,并练习 Collections 工具类的查找方法。
|
|
|
|
|
+
|
|
|
|
|
+**题目要求**:
|
|
|
|
|
+
|
|
|
|
|
+1. 定义 `Product` 类(`name`、`price`、`stock`,补全 getter/setter/toString):
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+// Product.java
|
|
|
|
|
+public class Product {
|
|
|
|
|
+ private String name;
|
|
|
|
|
+ private double price;
|
|
|
|
|
+ private int stock;
|
|
|
|
|
+
|
|
|
|
|
+ public Product(String name, double price, int stock) {
|
|
|
|
|
+ this.name = name;
|
|
|
|
|
+ this.price = price;
|
|
|
|
|
+ this.stock = stock;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 补全 getter / setter / toString 方法
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. 编写 `ProductSortDemo`:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.Collections;
|
|
|
|
|
+import java.util.Comparator;
|
|
|
|
|
+
|
|
|
|
|
+public class ProductSortDemo {
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
|
+ // 1. 创建 ArrayList<Product>,添加 5 个商品:
|
|
|
|
|
+ // 苹果 3.5 100 / 香蕉 2.0 200 / 西瓜 6.8 50 / 葡萄 12.5 80 / 橙子 5.0 150
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 匿名内部类 Comparator:按价格升序排序
|
|
|
|
|
+ // 提示:Collections.sort(list, new Comparator<Product>() {
|
|
|
|
|
+ // public int compare(Product p1, Product p2) {
|
|
|
|
|
+ // return Double.compare(p1.getPrice(), p2.getPrice());
|
|
|
|
|
+ // }
|
|
|
|
|
+ // });
|
|
|
|
|
+ // 遍历输出
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 匿名内部类 Comparator:按价格【降序】排序(交换参数位置)
|
|
|
|
|
+ // 遍历输出
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 匿名内部类 Comparator:按库存升序排序(int 直接相减)
|
|
|
|
|
+ // 遍历输出
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 用 Collections.max(list, comparator) 找出价格最高的商品
|
|
|
|
|
+ // Collections.min(list, comparator) 找出价格最低的商品
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 用 Collections.binarySearch(list, 目标商品, comparator) 查找(先按价格排序再查找)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**预期输出**(节选):
|
|
|
|
|
+```
|
|
|
|
|
+========== 按价格升序 ==========
|
|
|
|
|
+香蕉 2.0 200
|
|
|
|
|
+苹果 3.5 100
|
|
|
|
|
+橙子 5.0 150
|
|
|
|
|
+西瓜 6.8 50
|
|
|
|
|
+葡萄 12.5 80
|
|
|
|
|
+========== 按价格降序 ==========
|
|
|
|
|
+葡萄 12.5 80
|
|
|
|
|
+西瓜 6.8 50
|
|
|
|
|
+橙子 5.0 150
|
|
|
|
|
+苹果 3.5 100
|
|
|
|
|
+香蕉 2.0 200
|
|
|
|
|
+========== 按库存升序 ==========
|
|
|
|
|
+西瓜 6.8 50
|
|
|
|
|
+葡萄 12.5 80
|
|
|
|
|
+苹果 3.5 100
|
|
|
|
|
+橙子 5.0 150
|
|
|
|
|
+香蕉 2.0 200
|
|
|
|
|
+价格最高的商品:葡萄 12.5
|
|
|
|
|
+价格最低的商品:香蕉 2.0
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**思考题**(选做,不要求提交代码):
|
|
|
|
|
+1. double 类型的价格为什么不能用 `(int)(p1.getPrice() - p2.getPrice())`?(提示:浮点精度 + 强转截断)
|
|
|
|
|
+2. 想让 Comparator 排序方向反过来,最简单的做法是什么?(提示:交换 compare 中两个参数的位置)
|
|
|
|
|
+3. `Collections.binarySearch` 使用前提是什么?(提示:查找前必须先按相同规则排序)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 作业 3:可变参数 Varargs — 任意个数成绩统计
|
|
|
|
|
+
|
|
|
|
|
+**包名**:`p3_varargs`
|
|
|
|
|
+
|
|
|
|
|
+**知识点**:可变参数 `int... a`、`for each` 遍历、**可变参数本质即数组**、**固定参数 + 可变参数(可变参数置末)**、求总分/平均分/最高分
|
|
|
|
|
+
|
|
|
|
|
+**场景描述**:用**可变参数**实现"任意个数成绩的统计"——一个方法接收 2 个、3 个、5 个...任意个数的成绩,并计算总分、平均分、最高分。
|
|
|
|
|
+
|
|
|
|
|
+**题目要求**:
|
|
|
|
|
+
|
|
|
|
|
+1. 定义 `Calculator` 类,实现 `add(int... a)` 任意个数整数求和:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+// Calculator.java
|
|
|
|
|
+public class Calculator {
|
|
|
|
|
+ // TODO: 可变参数方法 add(int... a),累加求和
|
|
|
|
|
+ // 提示:int sum = 0;
|
|
|
|
|
+ // for (int n : a) { sum += n; }
|
|
|
|
|
+ // return sum;
|
|
|
|
|
+ public int add(int... a) {
|
|
|
|
|
+ return 0; // 请补全
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. 定义 `ScoreCalculator` 类,实现"固定参数 + 可变参数"的成绩统计:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+// ScoreCalculator.java
|
|
|
|
|
+public class ScoreCalculator {
|
|
|
|
|
+ // TODO: showScore(String name, int... scores)
|
|
|
|
|
+ // 1) 输出学生姓名
|
|
|
|
|
+ // 2) 遍历 scores 求总分(total)和最高分(max)
|
|
|
|
|
+ // 3) 输出各科成绩、总分、平均分(total * 1.0 / scores.length)
|
|
|
|
|
+
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
|
+ Calculator calc = new Calculator();
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 同一个 add 方法,传入不同个数的参数:
|
|
|
|
|
+ // add(1, 2) → 3
|
|
|
|
|
+ // add(1, 2, 3) → 6
|
|
|
|
|
+ // add(1, 2, 3, 4, 5) → 15
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 验证"可变参数本质就是数组":用 int[] 调用 add(arr)
|
|
|
|
|
+
|
|
|
|
|
+ ScoreCalculator sc = new ScoreCalculator();
|
|
|
|
|
+ // 3. 张三 3 门课:85, 90, 78
|
|
|
|
|
+ // 4. 李四 5 门课:92, 88, 95, 80, 90
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**预期输出**:
|
|
|
|
|
+```
|
|
|
|
|
+add(1, 2) = 3
|
|
|
|
|
+add(1, 2, 3) = 6
|
|
|
|
|
+add(1, 2, 3, 4, 5) = 15
|
|
|
|
|
+用数组调用 add(arr) = 15
|
|
|
|
|
+========== 张三的成绩单 ==========
|
|
|
|
|
+姓名:张三
|
|
|
|
|
+各科成绩:85, 90, 78
|
|
|
|
|
+总分:253,平均分:84.33,最高分:90
|
|
|
|
|
+========== 李四的成绩单 ==========
|
|
|
|
|
+姓名:李四
|
|
|
|
|
+各科成绩:92, 88, 95, 80, 90
|
|
|
|
|
+总分:445,平均分:89.0,最高分:95
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**思考题**(选做,不要求提交代码):
|
|
|
|
|
+1. `int... a` 和 `int[] a` 是什么关系?为什么调用效果一样?(提示:可变参数是数组的语法糖)
|
|
|
|
|
+2. `showScore(String name, int... scores)` 中可变参数能写在 name 前面吗?(提示:可变参数必须放在参数列表最后)
|
|
|
|
|
+3. 如果调用 `showScore("王五")`(不传成绩),`scores.length` 是多少?会不会报错?
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# 第二部分:进阶题(⭐⭐ 必做)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 作业 4:Lambda 表达式 — 简化接口实现与排序
|
|
|
|
|
+
|
|
|
|
|
+**包名**:`p4_lambda`
|
|
|
|
|
+
|
|
|
|
|
+**知识点**:**函数式接口**、Lambda 标准格式 `(参数)->{代码块}`、**三条省略规则**(类型可全省 / 单参数省小括号 / 单语句省大括号分号 return)、`Collections.sort` + Lambda
|
|
|
|
|
+
|
|
|
|
|
+**场景描述**:今日课上新学了 Lambda 表达式——它是**另一种形式的匿名内部类**,能大幅简化代码。要求用 Lambda 实现两个函数式接口,并用 Lambda 改写 `Collections.sort` 的排序代码,体会省略模式的便捷。
|
|
|
|
|
+
|
|
|
|
|
+**题目要求**:
|
|
|
|
|
+
|
|
|
|
|
+1. 定义两个函数式接口:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+// Addable.java —— 有参有返回值
|
|
|
|
|
+public interface Addable {
|
|
|
|
|
+ int add(int x, int y);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// Flyable.java —— 有参无返回值
|
|
|
|
|
+public interface Flyable {
|
|
|
|
|
+ void fly(String s);
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. 编写 `LambdaDemo`:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+public class LambdaDemo {
|
|
|
|
|
+ public static void useAdd(Addable a) {
|
|
|
|
|
+ System.out.println(a.add(10, 20));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static void useFlyable(Flyable f) {
|
|
|
|
|
+ f.fly("今天天气不错...是风和日丽的...");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
|
+ // 1. Addable:完整写法 useAdd((a, b) -> { return a + b; });
|
|
|
|
|
+ // 省略写法:代码块只有一条语句 → 省略大括号、分号、return
|
|
|
|
|
+ useAdd((a, b) -> a + b);
|
|
|
|
|
+
|
|
|
|
|
+ // 2. Flyable:参数有且只有一个 → 小括号可以省略
|
|
|
|
|
+ useFlyable(s -> {
|
|
|
|
|
+ System.out.println(s);
|
|
|
|
|
+ System.out.println("长翅膀....飞...");
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 用 Lambda 改写 Collections.sort:定义学生集合,按成绩升序排序
|
|
|
|
|
+ // 对比匿名内部类写法:
|
|
|
|
|
+ // Collections.sort(list, new Comparator<Student>() {...});
|
|
|
|
|
+ // Lambda 写法:Collections.sort(list, (s1, s2) -> ...);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+3. **进阶挑战**:定义一个 `Product` 类(名称 + 价格),用 **Lambda + Collections.sort** 按价格降序排序输出(提示:`Double.compare(s2.getPrice(), s1.getPrice())`)。
|
|
|
|
|
+
|
|
|
|
|
+**预期输出**:
|
|
|
|
|
+```
|
|
|
|
|
+30
|
|
|
|
|
+今天天气不错...是风和日丽的...
|
|
|
|
|
+长翅膀....飞...
|
|
|
|
|
+========== Collections.sort 用 Lambda 排序 ==========
|
|
|
|
|
+(按你的学生/商品数据排序输出)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**思考题**(选做,不要求提交代码):
|
|
|
|
|
+1. Lambda 表达式的三要素是什么?三条省略规则分别是什么?
|
|
|
|
|
+2. 为什么 Lambda 只能用在**只有一个抽象方法**的接口上?(提示:函数式接口,`()` 才能唯一确定指向它)
|
|
|
|
|
+3. Lambda 与匿名内部类的本质区别是什么?(提示:编译期是否产生独立 .class 文件)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 作业 5:综合应用 — 员工信息管理系统
|
|
|
|
|
+
|
|
|
|
|
+**包名**:`p5_employee`
|
|
|
|
|
+
|
|
|
|
|
+**知识点**:**Comparable 自然排序** + **equals/hashCode 一致性** + `TreeSet` 自动排序/去重 + **匿名内部类或 Lambda 按姓名排序** + 迭代器遍历
|
|
|
|
|
+
|
|
|
|
|
+**场景描述**:某公司员工信息管理系统。`Employee` 类(工号、姓名、薪资、部门)要求:
|
|
|
|
|
+- **默认排序**:按薪资降序,薪资相同再按工号(自然排序)
|
|
|
|
|
+- 存入 TreeSet 后**自动排序**且**自动去重**(工号相同的员工视为同一人 → equals/hashCode 与 compareTo 判定口径一致)
|
|
|
|
|
+- 临时需求:按姓名排序输出一份通讯录(**不修改 Employee 类**,用 Comparator 匿名内部类或 Lambda)
|
|
|
|
|
+
|
|
|
|
|
+**题目要求**:
|
|
|
|
|
+
|
|
|
|
|
+1. 定义 `Employee` 类:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+import java.util.Objects;
|
|
|
|
|
+
|
|
|
|
|
+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 方法
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 重写 compareTo —— 按薪资降序,薪资相同再按工号
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public int compareTo(Employee o) {
|
|
|
|
|
+ // 提示:int result = Double.compare(o.getSalary(), this.salary); // 降序
|
|
|
|
|
+ // return result == 0 ? this.id.compareTo(o.getId()) : result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // TODO: 重写 equals / hashCode —— 与 compareTo 判定口径一致(以工号判定)
|
|
|
|
|
+ // 提示:equals 用 Objects.equals(id, employee.id);hashCode 用 Objects.hash(id)
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. 编写 `EmployeeSystem`:
|
|
|
|
|
+
|
|
|
|
|
+```java
|
|
|
|
|
+import java.util.Comparator;
|
|
|
|
|
+import java.util.Iterator;
|
|
|
|
|
+import java.util.TreeSet;
|
|
|
|
|
+
|
|
|
|
|
+public class EmployeeSystem {
|
|
|
|
|
+ public static void main(String[] args) {
|
|
|
|
|
+ // 1. 创建 TreeSet<Employee>(自然排序)
|
|
|
|
|
+ // 添加 5 名员工(其中两名工号相同,测试去重):
|
|
|
|
|
+ // E001-张三-12000-技术部 / E002-李四-15000-市场部
|
|
|
|
|
+ // E003-王五-15000-技术部 / E004-赵六-9000-财务部
|
|
|
|
|
+ // E005-刘七-12000-市场部 / 再添加一个工号重复的 E002-李四-20000-市场部
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 迭代器遍历输出 → 观察:按薪资降序,薪资相同按工号;工号重复的自动去重
|
|
|
|
|
+ // 输出格式:"E001-张三-12000.0-技术部"
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 通讯录按姓名排序:重新创建 TreeSet,传入按姓名排序的 Comparator
|
|
|
|
|
+ // (可用匿名内部类,也可尝试用 Lambda:Comparator.comparing(Employee::getName) 或
|
|
|
|
|
+ // (o1, o2) -> o1.getName().compareTo(o2.getName()))
|
|
|
|
|
+ // 迭代器遍历输出
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**预期输出**:
|
|
|
|
|
+```
|
|
|
|
|
+========== 默认排序:按薪资降序(薪资相同按工号) ==========
|
|
|
|
|
+E002-李四-15000.0-市场部
|
|
|
|
|
+E003-王五-15000.0-技术部
|
|
|
|
|
+E001-张三-12000.0-技术部
|
|
|
|
|
+E005-刘七-12000.0-市场部
|
|
|
|
|
+E004-赵六-9000.0-财务部
|
|
|
|
|
+========== 通讯录:按姓名排序 ==========
|
|
|
|
|
+E002-李四-15000.0-市场部
|
|
|
|
|
+E005-刘七-12000.0-市场部
|
|
|
|
|
+E003-王五-15000.0-技术部
|
|
|
|
|
+E001-张三-12000.0-技术部
|
|
|
|
|
+E004-赵六-9000.0-财务部
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**原理分析(必答,写在代码注释或提交说明中)**:
|
|
|
|
|
+1. 为什么 E002 添加两次却只存了一个?—— `compareTo` 工号相同返回 0,视为重复,第二次 `add` 不生效
|
|
|
|
|
+2. 为什么 `equals` / `hashCode` 要以**工号**为判定依据?—— 与 `compareTo` 判定口径一致,官方推荐 `compareTo == 0 → equals 返回 true、hashCode 一致`
|
|
|
|
|
+3. 临时按姓名排序为什么不用修改 Employee 类?—— 用 Comparator(匿名内部类 / Lambda),排序规则在集合这边
|
|
|
|
|
+
|
|
|
|
|
+**思考题**(选做,不要求提交代码):
|
|
|
|
|
+1. `Collections.sort` 和 `TreeSet` 自动排序有什么区别?(提示:前者改变已有 List 顺序,后者存入时排序且去重)
|
|
|
|
|
+2. 用 Lambda 重写按姓名排序的 Comparator 怎么写?(提示:`(o1, o2) -> o1.getName().compareTo(o2.getName())`)
|
|
|
|
|
+3. 如果 TreeSet 添加的员工**工号和薪资都相同**但姓名不同,能都存入吗?`equals` 会返回 true 吗?(提示:compareTo 返回 0 视为重复不存;equals 以工号判定也会返回 true——口径一致)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# 第三部分:简答题(必做)
|
|
|
|
|
+
|
|
|
|
|
+## 简答题:Lambda 表达式与匿名内部类的区别
|
|
|
|
|
+
|
|
|
|
|
+请用文字说明(可配合示例代码)回答以下问题:
|
|
|
|
|
+
|
|
|
|
|
+1. **Lambda 表达式的标准格式和三要素是什么?** `(形式参数)->{代码块}` 各部分分别对应什么?
|
|
|
|
|
+2. **Lambda 有哪些省略规则?** 请各举一个例子说明。
|
|
|
|
|
+3. **Lambda 和匿名内部类有什么区别?** 请从以下三个维度回答:
|
|
|
|
|
+ - 需要的类型(接口 / 抽象类 / 普通类)
|
|
|
|
|
+ - 使用限制(抽象方法个数)
|
|
|
|
|
+ - 编译原理(是否产生独立的 .class 文件)
|
|
|
|
|
+
|
|
|
|
|
+**答题要点提示**:
|
|
|
|
|
+- 标准格式:`(形式参数) -> {代码块}`;三要素:形式参数、箭头、代码块
|
|
|
|
|
+- 三条省略规则:参数类型可全省(不能只省一个);单参数可省小括号;单语句可省大括号/分号/return
|
|
|
|
|
+- 区别:
|
|
|
|
|
+ - 需要的类型:匿名内部类可以是**接口、抽象类、普通具体类**;Lambda **只能是接口**
|
|
|
|
|
+ - 使用限制:接口有多个抽象方法只能用匿名内部类;Lambda 要求**有且只有一个抽象方法**(函数式接口)
|
|
|
|
|
+ - 编译原理:匿名内部类编译产生**独立的 .class 文件**;Lambda 编译**不产生 .class 文件**,字节码在**运行期动态生成**
|
|
|
|
|
+
|