课后 10.8
import java.util.Random;
import java.util.Scanner;
import java.util.HashSet;
import java.util.Timer;
import java.util.TimerTask;
public class Math {
private static HashSet
private static int total = 0;
private static int correct = 0;
private static int wrong = 0;
private static boolean isTimeUp = false;
private static int timeLimit;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入答题时间(秒):");
timeLimit = sc.nextInt();
startCountdown();
makeQuestion();
showResult();
sc.close();
}
private static void startCountdown() {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (timeLimit <= 0) {
isTimeUp = true;
System.out.println("\n时间到!");
timer.cancel();
} else if (timeLimit <= 10) { // 最后10秒提醒
System.out.println("剩余时间:" + timeLimit + "秒");
}
timeLimit--;
}
}, 0, 1000);
}
private static void showResult() {
System.out.println("\n===== 答题结果 =====");
System.out.println("总题数:" + total);
System.out.println("做对:" + correct);
System.out.println("做错:" + wrong);
if (total > 0) {
System.out.println("正确率:" + (correct * 100.0 / total) + "%");
}
}
public static void makeQuestion() {
for (int i = 0; i < 30 && !isTimeUp; i++) {
Random num = new Random();
int end = 0;
char op=' ';
boolean check=false;
int num1 = num.nextInt(100);
int num2 = num.nextInt(100);
int num_meddle = num.nextInt(4);
switch (num_meddle) {
case 0:
end = num1 + num2;
op = '+';
break;
case 1:
end = num1 - num2;
op = '-';
break;
case 2:
end = num1 * num2;
op = '*';
break;
case 3:
end = num1 / num2;
op = '/';
break;
}
// 检查题目有效性和重复性
check = checkQuestion(num1, num2, op);
String question = num1 + "" + op + "" + num2 + "=";
// 如果题目无效或重复,重新生成
if (!check || questionSet.contains(question) || isTimeUp) {
i--;
continue;
}
// 除法需要重新计算正确结果
if (op == '/') {
end = num1 / num2;
}
// 记录已出现的题目
questionSet.add(question);
total++;
// 显示题目并处理答题
System.out.print(question);
if (isTimeUp) {
wrong++;
continue;
}
// 处理答题结果
if (answerQuestion(end)) {
correct++;
System.out.println("正确");
} else {
wrong++;
System.out.println("错误,正确答案是:" + end);
}
}
}
public static boolean answerQuestion(int end) {
if (isTimeUp) return false;
Scanner input = new Scanner(System.in);
try {
int answer = input.nextInt();
return answer == end;
} catch (Exception e) {
return false;
}
}
public static boolean checkQuestion(int num1, int num2, char op) {
switch (op) {
case '-':
return num1 >= num2;
case '*':
return num1 * num2 < 1000;
case '/':
return num2 != 0 && num1 % num2 == 0;
default: // '+'
return true;
}
}
}
学完这节 Java 方法课,最大的感受是之前对 “方法” 的理解太浅了 —— 原来它不只是写个函数那么简单,而是像 PPT 里说的 “懒人造就方法”,把复杂问题拆成小块、重复利用。比如百万行代码分模块那例子,以前总觉得把代码堆在一起也能跑,直到自己试着写一个小工具时,把所有逻辑塞在 main 方法里,后来想改个答题计时功能,差点把整个代码搅乱,这才真正懂了模块化的意义:把计时、出题、判题拆成独立方法后,改其中一个功能时,其他部分完全不受影响,维护起来特别清爽。
还有处理大数字和浮点数的坑,印象特别深。之前算 20 的阶乘,用 int 类型结果变成了负数,换成 long 类型后,算到 30 的阶乘又不对了,翻 PPT 才想起 “类型有范围限制”,赶紧换成 BigInteger,看着控制台输出一长串正确的数字,才真正意识到基础类型的边界不是摆设。浮点数的坑也踩过,一开始用 == 比较 0.1+0.2 和 0.3,结果输出 false,当时还以为是代码写错了,后来按 PPT 里说的 “比差值绝对值”,用 Math.abs ((0.1+0.2)-0.3) < 1e-10 来判断,才得到正确结果,这些细节在课本上看时没太在意,实际写代码时却很容易掉进去
最后做四则运算的作业时,才算把零散的知识点串了起来:用 Random 类生成数字时,一开始没考虑除法要整除,后来加了判断 “num1 % num2 == 0”;遇到重复题目时,想起 HashSet 不存重复元素,就用它来记录已出的题目;还试着用方法重载写了两个判题方法,一个判整数答案,一个判浮点数答案(虽然最后作业没用到浮点数,但也算练了手)。做完后把随机数生成、题目合法性校验的方法整理到一个工具类里,下次同学要做类似作业时,直接把这个类发给他,他改改参数就能用,这才体会到整理代码仓库的必要 —— 不是为了 “存着”,而是下次遇到类似问题时,不用从头写起,效率能高很多。

浙公网安备 33010602011771号