南昌航空大学-软件学院-22207107-胡优乐-JAVA第一次Blog作业
前言
距离开学第一次接触java已然过去了将近两个月时间,在这段时间里我们总共进行了三次大作业联系,基于这三次大作业的体量及设计的知识点,难度分布,我做了以下的总结:
1.第一次大作业总共有五题,分别是:1.设计一个风扇的类,2.类和对象的使用,3.成绩设计1-类,数组的基本运用,4.成绩设计2-关联类,5.答题程序1。实际做下来的体会是:
(1)第一题难度入门级别,涉及的知识点是设计类,创建该类的对象并输出其状态,常量定义,私有成员变量,toString等。
(2)第二题难度入门级别,涉及到的知识点是创建一个简单的学生类,并通过构造器、访问器、修改器和重写 toString 方法来处理学生的属性。
(3)第三题难度为基础,涉及的知识点是面向对象编程:使用类和对象封装学生的信息及行为;构造方法用于执行特定功能的函数,计算总分、平均分;使用数组存储多个学生对象;将输入行分隔为多个部分,方便提取数据。
(4)第四题难度难度为基础,涉及的知识点主要是关联类,创建一个 Course 类来表示课程的信息和成绩,然后将其与 Student 类关联。
(5)第五题难度为困难,涉及到的知识点主要是定义多个类,每个类负责特定的功能,方法的定义和使用(添加题目,保存答案等)以及数据结构(HashMap和Array List)允许高效的查找和插入,正则表达式的基本运用。
2.第二次大作业共有五道题:
第一题 手机按价格排序、查找,难度:一般。涉及的知识点主要是:Comparable接口;Collections.sort(phoneList)对phoneList中的手机对象进行排序;
第二题 sdut-oop-4-求圆的面积(类与对象)难度:简单。涉及的知识点:类和对象,有参无参方法构造,方法,调用方法。
第三题 汽车类 难度:入门。涉及的知识:类和对象,方法。通过在Main类中创建Car对象(例如Car car = new Car("bob", 0.0f, 0.0f);),我们可以对汽车进行操作。
第四题 答题程序2 难度:困难。答题程序2相较于1增加了试卷信息,涉及的知识:正则表达式,
2.第三次大作业共有三道题:
第一题 面向对象编程(封装性) 难度:简单。 涉及的知识: 类和对象;成员变量私有化;构造方法;访问器修改器;数据验证。
第二题 jmu-java-日期类的基本使用 难度:简单。涉及的知识:LocalDate;ChronoUnit;判断闰年;LocalDate.parse() 方法来尝试将字符串解析为日期;使用 split(" ") 方法将输入的日期范围字符串分割成开始日期和结束日期。
第三题 答题程序三 难度:困难。涉及的知识:
设计与分析
1.答题判题程序1
设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
1. 类的设计
1.1 Matter 类
功能: 封装单个题目的信息,包括题号、题干和正确答案。提供了获取这些信息的方法以及用来判断用户答案是否正确的功能。
成员变量:
id: 题号
idcontent: 题干
ZQAnswer: 正确答案
方法:
构造器用于初始化题目信息。
judgeAnswer(String answer): 用于验证给定答案与标准答案是否一致。
public boolean judgeAnswer(String answer) {
return ZQAnswer.trim().equals(answer.trim());
}
1.2 testPaper 类
功能: 封装整张试卷的信息(题目没有规定多张试卷默认一张试卷),包含题目集合和题目数量的统计。提供了添加题目和获取题目的方法。
成员变量:
private HashMap<Integer, Matter> matters;
private int nums;
matters: 存储题目的 HashMap,以题号为键,题目为值。
number: 题目的数量。
方法:
addMatter(Matter item): 添加题目。
getMatter(int id): 获取指定题号的题目。
getMatterCount(): 获取题目总数。
1.3 Responsepaper 类
功能: 封装用户的答卷信息,包括试卷和用户的答案。提供了保存答案、验证答案以及输出结果的功能。
成员变量:
exam: 关联的试卷,类型为 testPaper 的对象,表示当前与之关联的试卷。这使得 Responsepaper 可以访问试卷中的题目及其正确答案
answers: 存储用户答案的列表。
results: 存储答题结果(正确与否)的列表。
方法:
savedaan(String daan): 记录用户的答案。
judgeAnswers(): 验证所有答案的正确性并保存结果。
public void judgeAnswers() {
for (int i = 0; i < answers.size(); i++) {
Matter matter = exam.getMatter(i + 1); // 假设题号从1开始
if (matter != null) {
boolean result = matter.judgeAnswer(answers.get(i));
results.add(result);
} else {
results.add(false); // 对于不存在的题目,记录为错误
}
}
}
这个方法遍历用户的答案列表,将每个答案与对应的题目进行比对。通过调用试卷中的 getMatter() 方法获取对应题目,然后调用题目的 judgeAnswer() 方法进行判断,并将结果添加到 results 列表中。
putresults(): 打印用户的答案和判题结果。
1.4主类
功能:题目输入(循环控制,读取一行用户的输入,字符串处理,提取题号,提取题目内容,提取题目答案,创建Matter对象并添加到题库中。)for (int i = 0; i < Counts; i++) {
String x = scanner.nextLine().trim();
String[] nums = x.split("#");
int number = Integer.parseInt(nums[1].split(":")[1].strip());
String content = nums[2].split(":")[1].strip();
String answer = nums[3].split(":")[1].strip();
paper.addMatter(new Matter(number, content, answer));
}
输入作答(创建对象,读取用户输入答案直到输入end,处理字符串,遍历答案,检查格式,保存到对象中)
Responsepaper responsepaper = new Responsepaper(paper);
String inputAnswer;
while (!(inputAnswer = scanner.nextLine().trim()).equals("end")) {
String[] answers = inputAnswer.split("#");
for (String ans : answers) {
if (ans.startsWith("A:")) {
responsepaper.savedaan(ans.split(":")[1].strip());
}
}
}
通过调用 judgeAnswers() 方法来对用户的答案进行评判,并调用 putresults() 方法输出判题结果。
类图:
``
顺序图:
2.答题判题程序2
答题判题程序2相比于1的难度增加了不少,加上我开始的时间玩,最后只得了36分,很是可惜,事后我又认真地分析了这次题目,它在答题程序2的基础上增加了试卷的信息,并且题目信息、试卷信息和答题信息这三种信息可能会被打乱顺序混合输入。
为此,我在答题1的基础上做了一些改动。
题目类:保持原来功能不变;
试卷类:增加了试卷编号、对应的分值,返回试卷总分和题目数量的方法。
答卷类:保存答卷对应的试卷编号,答案,和判题结果。新增了试卷有效性判断标志,并调整了答案评估函数。
主类:增加了试卷集合和答卷集合来确保对多张试卷的处理,保存并统计试卷及其答案,根据标答判断答案的正确性,输出总分警告及每道题的答题结果。
2.1试卷类
number: 记录试卷中题目的数量。初始化为0,每当添加一道题目时自增1。
matters: 一个 LinkedHashMap 用于存储题目ID及其对应的分数。使用 LinkedHashMap 是为了维护插入顺序,方便后续可能的遍历操作。
fullpoints: 记录试卷的总分,初始化为0。每添加一道题目时,该分数累加。
2.2答卷类
id (int): 表示此答卷的唯一标识符。每个答卷都会有一个 ID,用以唯一识别这份答卷。
counts (int): 表示答卷中题目的数量。这个属性用于追踪该份答卷中包含了多少个问题。
answers (List
results (List
方法:返回答卷号 答卷的题目数量 答案列表 记录每个答案的判题结果并返回
2.3主类
题目、试卷、答案的输入解析:
通过不同的标志符(#N:、#T:、#S:)来区分输入的类型。
对每种输入类型使用正则表达式来提取相应的数据
检测到 #N: 开头的输入,提取题号、内容和标准答案,创建 Matter 实例并存储在 matter 中。
检测到 #T: 开头的输入,提取试卷 ID 和题目分数,创建 TestPaper 实例并存储。
检测到 #S: 开头的输入,提取答卷 ID 和用户的答案,创建 Responsepaper 实例并存储在 ans 列表中。
检查所有试卷的总分:
在评分过程中,检查每份试卷的总分是否为 100,若不等于 100,输出警告信息。
输出用户的答案和评分结果:
遍历每个用户的答案,获取对应试卷的信息,比较用户的答案与标准答案。
输出每道题的表现(是否正确)、用户的答案和题目内容。
计算正确的题目得分并输出总分
类图
时序图
3.答题判题程序3
答题判题程序3在答题判题程序2的基础上增加了 学生类和删除题目信息,在我看来,难度大大增加,让我望而却步。
为了实现上述功能,我在原有代码基础上做了一些改动。
3.1InputProcessor 类
增加了一个新的类 InputProcessor,用于处理输入,减少主类的负担,增加代码后续的移植性。
正则表达式匹配: 使用正则表达式 #N:(\s\d+\s)#Q:(.)#A:(.) 来匹配输入格式。
字符串处理: 通过 indexOf 方法找到特定标记的位置,然后使用 substring 方法提取相关信息。
数据存储: 将提取的信息存储到 matter 映射中,创建一个新的 Matter 对象并添加到映射中。
功能: 处理试卷输入。
正则表达式匹配: 使用正则表达式 #T:\s(\d+)\s(\s\d+-\d+\s)* 来匹配输入格式。
字符串处理: 通过 Matcher 对象提取试卷ID和题目ID及对应分数。
数据存储: 创建一个新的 ExamPaper 对象,并将题目ID和分数添加到 ExamPaper 对象中,最后将 ExamPaper 对象存储到 exampaper 映射中。
处理学生答案输入。
正则表达式匹配: 使用正则表达式 #S:\s(\d+)\s+(\w)\s(#A:\s(\d+-?[^#])) 来匹配输入格式。
字符串处理: 通过 Matcher 对象提取试卷ID、学生ID和答案内容。
数据存储: 将提取的答案内容存储到 an 映射中,创建一个新的 Answer 对象并添加到 ans 链表中。
处理学生信息输入。
正则表达式匹配: 使用正则表达式 #X:\s(\d+)\s(.)(-(\d+)\s(.)) 来匹配输入格式。
字符串处理: 通过 Matcher 对象提取学生ID和姓名。
数据存储: 创建一个新的 Student 对象并添加到 studentlist 链表中。
处理无效题目输入。
正则表达式匹配: 使用正则表达式 #D:N-\s(\d+)\s 来匹配输入格式。
字符串处理: 通过 Matcher 对象提取题目ID。
数据更新: 将对应题目的 judgeanswer 属性设置为 false,标记该题目为无效。
3.2学生类
定义了学生的属性和基本操作
3.3答卷类
增加了封装学生答题信息功能
3.4主类
- 检查试卷总分是否为100
for (int indea : exampaper.keySet()) {
ExamPaper paper = exampaper.get(indea);
int totalPoint = paper.getTotalpoint();
if (totalPoint != 100) {
System.out.println("alert: full score of test paper" + indea + " is not 100 points");
}
}
2.处理学生答案
获取试卷ID: 通过 a.getid() 获取当前答案对应的试卷ID。
检查试卷是否存在: 如果试卷不存在,输出提示信息并跳过当前答案的处理。
查找学生: 遍历 studentlist,查找与当前答案对应的学生。如果找到学生,设置 symbol 为1,并记录学生信息。
遍历试卷题目: 遍历当前试卷的所有题目,检查学生答案是否正确,并将判断结果存储到 consequns 列表中。
处理答案输出:
答案数量为0: 如果答案数量为0,输出 "answer is null",并输出学生的总分为0。
答案数量不为0: 遍历试卷的所有题目,输出每个题目的答案和判断结果。如果学生答案存在且题目有效且答案正确,输出题目的分数;否则输出0。最后输出学生的总分。
类图
时序图
踩坑心得
1.拖延症,一定要早点开始写pta大作业,随着难度的增加,完成一次大作业所需的时间也随之增加,如果不尽早开始的后果就是完成不了或者质量很差。
2.类的设计简单,各个类的关联性不强,导致第三次大作业的难度增加 需要在主类里加很多功能,导致代码的简洁性不强,对于下一次的大作业不能很好迁移。
3.懒惰心理,一开始不愿意吸收新知识,正则表达式,导致浪费了很多时间,正则表达式看似复杂实际上实用性很强,能减少本次大作业的不少压力
4.方法的职责划分不清晰,导致代码难以理解和维护,遵循单一职责原则,每个方法只负责一个特定的任务。
5.代码的可读性很差,应当多加注释。
改进建议
(1)在代码中合理性地增加类的设计,不要把功能堆砌在一个类或者主类中,这样会使得代码赘余,更难理解,应该逐步将复杂的代码拆分成多个小方法,每个方法只做一件事。
(2)核心代码部分增加详尽的注释
总结
经过三次大作业的洗礼,或许是代码写的少缘故,面对压轴题的时候,我感觉脑力和精力被压榨,加上畏难心理,我总是把大题拖到最后来写,因此又导致了一系列糟糕的连锁反应,陷入了死循环。
所以,扎实的代码功力和知识储备是基石,克服自身的畏难心理也格外重要。其实我们上课认真听讲,总结和内化学堂上和课后学到的知识,并在面对代码量大无从下手的代码时,画好类图和思维导图,把大难题细化成小难题,逐一攻破,没有什么事情是不能迎刃而解的。
这样便可以,梳理出答题判题程序的总体思路
比如第三次大作业的主要功能是处理学生答题和判题的过程。程序通过读取用户输入的不同类型的数据(如题目、试卷、学生答案和学生信息),进行相应的处理和存储,最后输出判题结果。程序的整体思路可以分为以下几个步骤:
输入处理:读取用户输入,根据输入的不同类型(如题目、试卷、学生答案、学生信息等)进行相应的处理和存储。
数据存储:将处理后的数据存储到相应的数据结构中(如 LinkedHashMap、LinkedList 等)。
输出处理:根据存储的数据进行判题,并输出判题结果。最终我们需要设计合理的类,通过详细的注释和合理的代码结构,去提高代码的可读性和可维护
三次大作业不是结束,而是开始,老师说,未来大作业的难度还会提高,所以,道阻且长,行则将至。