Przeglądaj źródła

feat: 新增20260803课堂练习可变参数专项——练习4任意个数整数求和(int... a)与练习5学生成绩统计(固定参数+可变参数、可变参数置末、总分/平均分/最高分/join拼接),含参考答案与知识点总览,同步更新README

WanJL 3 tygodni temu
rodzic
commit
13d31d5c89
2 zmienionych plików z 203 dodań i 4 usunięć
  1. 1 1
      README.md
  2. 202 3
      课堂练习题/20260803-比较器排序练习.md

+ 1 - 1
README.md

@@ -79,4 +79,4 @@
 | 2026-07-29 | [集合框架练习](./课堂练习题/20260729-集合框架练习.md) | ArrayList 基本操作(增删改查)、ArrayList 底层原理、包装类在集合中的应用、ArrayList 嵌套二维结构、冒泡排序、contains()/indexOf() 方法 |
 | 2026-07-30 | [LinkedList 双链表练习](./课堂练习题/20260730-LinkedList双链表练习.md) | LinkedList 作为 List 的基本操作、Deque 双端队列操作、Queue 队列 FIFO 操作、LinkedList vs ArrayList 性能对比实验、手写单链表增删改查 |
 | 2026-07-31 | [Iterator迭代器与Map集合练习](./课堂练习题/20260731-迭代器与Map集合练习.md) | Iterator 迭代器遍历(for vs 迭代器,hasNext/next)、HashMap 键值对基本操作(put/get/containsKey/containsValue/size/remove/clear)、Map 两种遍历方式(keySet+get / entrySet+getKey/getValue)、自定义类型作为 Key(重写 hashCode/equals)、HashMap 底层原理应用、单词词频统计 |
-| 2026-08-03 | [比较器排序练习](./课堂练习题/20260803-比较器排序练习.md) | Comparable 接口与 compareTo 重写、返回值规则(负数存左/0 重复不存/正数存右)、二次比较(多字段排序)、Comparator 接口与匿名内部类、TreeSet(Comparator) 构造方法、Collections.sort(list, comparator)、Double.compare、降序技巧(交换参数)、TreeMap 按键排序、compareTo 与 equals/hashCode 一致性、TreeSet 自动排序 + 去重、Iterator 迭代器遍历 |
+| 2026-08-03 | [比较器排序与可变参数练习](./课堂练习题/20260803-比较器排序练习.md) | Comparable 接口与 compareTo 重写、返回值规则(负数存左/0 重复不存/正数存右)、二次比较(多字段排序)、Comparator 接口与匿名内部类、TreeSet(Comparator) 构造方法、Collections.sort(list, comparator)、Double.compare、降序技巧(交换参数)、TreeMap 按键排序、compareTo 与 equals/hashCode 一致性、TreeSet 自动排序 + 去重、Iterator 迭代器遍历;可变参数(参数个数可变、本质即数组、固定参数+可变参数共存且可变参数置末、求总分/平均分/最大值/join 拼接) |

+ 202 - 3
课堂练习题/20260803-比较器排序练习.md

@@ -1,8 +1,8 @@
-# 2026-08-03 比较器排序专项练习(课堂练习用)
+# 2026-08-03 比较器排序与可变参数专项练习(课堂练习用)
 
-> **说明**:以下习题围绕今日授课核心内容——**比较器排序(Comparable 自然排序 / Comparator 比较器排序)** 展开,涵盖 Comparable 接口实现与 `compareTo(T o)` 重写、Comparator 接口与匿名内部类、TreeSet/TreeMap 有序集合自动排序、返回值规则(负数存左 / 0 重复不存 / 正数存右)、`Collections.sort(list, comparator)`、`Double.compare`、compareTo 与 equals 一致性等知识点。
+> **说明**:以下习题围绕今日授课核心内容——**比较器排序(Comparable 自然排序 / Comparator 比较器排序)** 与 **可变参数(Varargs)** 展开,涵盖 Comparable 接口实现与 `compareTo(T o)` 重写、Comparator 接口与匿名内部类、TreeSet/TreeMap 有序集合自动排序、返回值规则(负数存左 / 0 重复不存 / 正数存右)、`Collections.sort(list, comparator)`、`Double.compare`、compareTo 与 equals 一致性、可变参数 `形参类型... 参数名`(本质即数组、可变参数必须放最后)等知识点。
 >
-> 题目分为 **基础练习**(Comparable 自然排序 / Comparator 比较器排序 / Collections.sort 排序,3 题)和 **进阶挑战**(比较器综合应用,2 题)。
+> 题目分为 **基础练习**(Comparable 自然排序 / Comparator 比较器排序 / Collections.sort 排序 / 可变参数,5 题)和 **进阶挑战**(比较器综合应用,2 题)。
 
 ---
 
@@ -173,6 +173,113 @@ public class ListSortTest {
 
 ---
 
+## 练习 4:可变参数基础——任意个数整数求和
+
+**难度**:⭐⭐
+**知识点**:可变参数 `int... a`、`for each` 遍历、方法重载 vs 可变参数、可变参数本质即数组
+
+**场景描述**:以前计算"多个整数相加",有几个参数就要定义几个**方法重载**(`add(int a, int b)` / `add(int a, int b, int c)`...),写多少个都覆盖不完。有了**可变参数**,一个方法就能接收**任意个数**的参数——**方便用户使用,也方便自己定义**。
+
+**题目要求**:
+
+1. 定义 `Calculator` 类,编写可变参数方法 `add(int... a)`,用 for each 累加求和:
+
+```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;  // 请补全
+    }
+
+    public static void main(String[] args) {
+        Calculator calc = new Calculator();
+
+        // 1. 同一个方法,传入不同个数的参数:
+        //    add(1, 2)                → 3
+        //    add(1, 2, 3)             → 6
+        //    add(1, 2, 3, 4, 5)       → 15
+        //    add(1,2,...,10)          → 55
+
+        // 2. 验证"可变参数本质就是数组":用数组调用,效果与直接传参数一致
+        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+        //    calc.add(arr)            → 55
+    }
+}
+```
+
+**预期输出**:
+```
+add(1, 2) = 3
+add(1, 2, 3) = 6
+add(1, 2, 3, 4, 5) = 15
+add(1~10 累加) = 55
+用数组调用 add(arr) = 55
+```
+
+**思考题**:
+1. `int... a` 和 `int[] a` 是什么关系?为什么两者调用效果一样?(提示:可变参数是数组的语法糖)
+2. 既然有了可变参数,为什么还要方法重载?(提示:参数**个数**不确定用可变参数;参数**个数固定、类型不同**用重载更清晰)
+3. 如果把 `add(int... a)` 改成 `add(int[] a)`,调用时还能写 `add(1, 2, 3)` 吗?(提示:不能,数组参数必须显式传数组)
+
+---
+
+## 练习 5:可变参数进阶——学生成绩统计(固定参数 + 可变参数)
+
+**难度**:⭐⭐
+**知识点**:固定参数与可变参数共存、**可变参数必须放在最后**、求总分/平均分/最大值、可变参数的综合应用
+
+**场景描述**:一个学生有多门课程成绩,成绩**个数不定**。要求:方法同时接收"学生姓名"(固定参数)和"若干门成绩"(可变参数),统计输出总分和平均分。**注意:可变参数必须放在参数列表的最后。**
+
+**题目要求**:
+
+1. 定义 `ScoreCalculator` 类,编写方法 `showScore(String name, int... scores)`:
+
+```java
+public class ScoreCalculator {
+    // TODO: 编写方法 showScore(String name, int... scores)
+    //   1) 输出学生姓名
+    //   2) 遍历 scores 求和(total)和求最大值(max)
+    //   3) 输出各科成绩、总分、平均分(平均分用 double,total * 1.0 / scores.length)
+
+    public static void main(String[] args) {
+        ScoreCalculator sc = new ScoreCalculator();
+        sc.showScore("张三", 85, 90, 78);          // 3 门课
+        sc.showScore("李四", 92, 88, 95, 80, 90);  // 5 门课
+    }
+}
+```
+
+2. **进阶挑战**:再实现两个可变参数方法,体会通用性:
+   - `max(int... a)`:返回任意个数整数中的最大值
+   - `join(String separator, String... strings)`:用分隔符拼接若干字符串,如 `join("-", "Java", "SE", "260713")` → `"Java-SE-260713"`(注意:固定参数 separator 在前,可变参数在后)
+
+**预期输出**:
+```
+========== 张三的成绩单 ==========
+姓名:张三
+各科成绩:85, 90, 78
+总分:253,平均分:84.33
+最高分:90
+========== 李四的成绩单 ==========
+姓名:李四
+各科成绩:92, 88, 95, 80, 90
+总分:445,平均分:89.0
+最高分:95
+========== 可变参数进阶 ==========
+max(3, 9, 5, 1) = 9
+join("-", "Java", "SE", "260713") = Java-SE-260713
+```
+
+**思考题**:
+1. `showScore(String name, int... scores)` 中,可变参数能写在 name 前面吗?为什么?(提示:可变参数必须放在参数列表最后,否则编译报错)
+2. 如果调用 `showScore("张三")`(不传成绩),`scores.length` 是多少?会不会报错?(提示:可变参数可传 0 个,scores 是长度为 0 的数组)
+3. `join` 方法为什么把分隔符 separator 放在前面、可变参数放后面?如果反过来 `join(String... strings, String separator)` 行吗?(提示:违背"可变参数置末"规则)
+
+---
+
 # 第二部分:进阶挑战
 
 > 以下练习综合运用 Comparable / Comparator、TreeMap、compareTo 与 equals 一致性等知识。
@@ -428,6 +535,93 @@ for (Student s : list) {
 }
 ```
 
+## 练习 4 参考
+
+```java
+public class Calculator {
+    // 可变参数:本质就是 int[] a
+    public int add(int... a) {
+        int sum = 0;
+        for (int n : a) {
+            sum += n;
+        }
+        return sum;
+    }
+
+    public static void main(String[] args) {
+        Calculator calc = new Calculator();
+
+        System.out.println("add(1, 2) = " + calc.add(1, 2));
+        System.out.println("add(1, 2, 3) = " + calc.add(1, 2, 3));
+        System.out.println("add(1, 2, 3, 4, 5) = " + calc.add(1, 2, 3, 4, 5));
+
+        int sum10 = calc.add(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+        System.out.println("add(1~10 累加) = " + sum10);
+
+        // 可变参数本质就是数组:用数组调用效果一致
+        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+        System.out.println("用数组调用 add(arr) = " + calc.add(arr));
+    }
+}
+```
+
+## 练习 5 参考
+
+```java
+public class ScoreCalculator {
+    // 固定参数 name + 可变参数 scores(可变参数必须放最后)
+    public void showScore(String name, int... scores) {
+        System.out.println("========== " + name + "的成绩单 ==========");
+        System.out.println("姓名:" + name);
+
+        int total = 0;
+        int max = scores[0];      // 假设至少有一门成绩
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < scores.length; i++) {
+            total += scores[i];
+            if (scores[i] > max) {
+                max = scores[i];
+            }
+            sb.append(scores[i]).append(i == scores.length - 1 ? "" : ", ");
+        }
+        System.out.println("各科成绩:" + sb);
+        System.out.println("总分:" + total + ",平均分:" + String.format("%.2f", total * 1.0 / scores.length));
+        System.out.println("最高分:" + max);
+    }
+
+    // 进阶:求任意个数整数的最大值
+    public int max(int... a) {
+        int max = a[0];
+        for (int n : a) {
+            if (n > max) max = n;
+        }
+        return max;
+    }
+
+    // 进阶:用分隔符拼接若干字符串(固定参数在前,可变参数在后)
+    public String join(String separator, String... strings) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < strings.length; i++) {
+            sb.append(strings[i]);
+            if (i != strings.length - 1) {
+                sb.append(separator);
+            }
+        }
+        return sb.toString();
+    }
+
+    public static void main(String[] args) {
+        ScoreCalculator sc = new ScoreCalculator();
+        sc.showScore("张三", 85, 90, 78);
+        sc.showScore("李四", 92, 88, 95, 80, 90);
+
+        System.out.println("========== 可变参数进阶 ==========");
+        System.out.println("max(3, 9, 5, 1) = " + sc.max(3, 9, 5, 1));
+        System.out.println("join(\"-\", \"Java\", \"SE\", \"260713\") = " + sc.join("-", "Java", "SE", "260713"));
+    }
+}
+```
+
 ## 进阶 1 参考
 
 ```java
@@ -520,4 +714,9 @@ for (Employee e : byName) {
 | compareTo 与 equals/hashCode 一致性 | 进阶 1、进阶 2 | compareTo == 0 → equals 返回 true、hashCode 一致 |
 | TreeSet 自动排序 + 去重 | 练习 1、进阶 2 | compareTo 返回 0 视为重复,不存入 |
 | Iterator 迭代器遍历 | 进阶 2 | Set 没有索引,用迭代器统一遍历 |
+| 可变参数定义与调用 | 练习 4、练习 5 | `int... a` 参数个数可变,一个方法接收任意个数参数 |
+| 可变参数本质即数组 | 练习 4 | `int... a` 等价于 `int[] a`,可用数组直接调用 |
+| 方法重载 vs 可变参数 | 练习 4 | 参数个数不确定用可变参数;个数固定、类型不同用重载 |
+| 固定参数 + 可变参数共存 | 练习 5 | 可变参数必须放在参数列表最后,否则编译报错 |
+| 可变参数综合应用 | 练习 5 | 求总分/平均分/最大值、字符串拼接 join |