南航航空大学第三次BLOG
前言
本次博客主要涵盖了Java题目的几个主要知识点,包括面向对象编程(Object-Oriented Programming, OOP)、类与对象、构造方法、访问权限、成员变量、继承和组合、异常处理、字符串处理以及控制流和数据结构。
在面向对象编程中,类是创建对象的蓝图或模板,而对象则是类的实例。构造方法用于在创建对象时初始化对象。访问权限修饰符决定了类、变量、方法和构造器的可访问性,包括private、protected、public和默认(不使用任何修饰符,也称为包私有级别)。
成员变量是类中定义的变量,根据其访问权限,可以被对象自身的方法、类中其他方法或外部方法访问。继承和组合是实现代码复用的两种方式,其中继承通过扩展现有的类来创建新类,而组合通过将其他对象的引用包含在当前对象中来实现代码复用。
异常处理是保证程序健壮性的重要环节,Java提供了try-catch-finally块来捕获和处理异常。字符串处理是通过String类实现的,提供了丰富的方法来进行字符串的操作,如拼接、分割、替换等。
控制流包括循环和条件语句,用于实现逻辑控制。数据结构如数组、列表、集合和映射等在Java中起着重要的作用,提供了存储和管理数据的方式,对于实现算法和功能逻辑至关重要。
综上所述,本次题目涵盖了面向对象编程的基本概念、构造方法和访问权限的使用、成员变量的定义与访问、继承和组合的原则、异常处理机制、字符串处理技巧以及控制流和数据结构的应用。这些知识点对于编写高效、可靠和可维护的Java程序至关重要。整体难度属于中等偏上,适合用来考察学生对面向对象设计原则和异常处理的理解。题目数量适中,涵盖了多个细节和需求,包括各种异常处理和特殊情况的处理。
设计与分析
1.课程成绩统计程序-2
题目要求
课程成绩统计程序-2在第一次的基础上增加了实验课,以下加粗字体显示为本次新增的内容。
某高校课程从性质上分为:必修课、选修课、实验课,从考核方式上分为:考试、考察、实验。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩0.3+期末成绩0.7。
考察的总成绩直接等于期末成绩
实验的总成绩等于课程每次实验成绩的平均分
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。实验课的成绩必须为实验。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式(可选,如果性质是必修课,考核方式可以没有)三个数据项。
课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
课程性质输入项:必修、选修、实验
考核方式输入选项:考试、考察、实验
考试/考查课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
考试/考查课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
实验课程成绩信息包括:学号、姓名、课程名称、实验次数、每次成绩
实验次数至少4次,不超过9次
实验课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+实验次数+英文空格+第一次实验成绩+...+英文空格+最后一次实验成绩
以上信息的相关约束:
1)平时成绩和期末成绩的权重默认为0.3、0.7
2)成绩是整数,不包含小数部分,成绩的取值范围是【0,100】
3)学号由8位数字组成
4)姓名不超过10个字符
5)课程名称不超过10个字符
6)不特别输入班级信息,班级号是学号的前6位。
2、输出:
输出包含三个部分,包括学生所有课程总成绩的平均分、单门课程成绩平均分、单门课程总成绩平均分、班级所有课程总成绩平均分。
为避免误差,平均分的计算方法为累加所有符合条件的单个成绩,最后除以总数。
1)学生课程总成绩平均分按学号由低到高排序输出
格式:学号+英文空格+姓名+英文空格+总成绩平均分
如果某个学生没有任何成绩信息,输出:学号+英文空格+姓名+英文空格+"did not take any exams"
2)单门课程成绩平均分分为三个分值:平时成绩平均分(可选)、期末考试平均分、总成绩平均分,按课程名称的字符顺序输出
考试/考察课程成绩格式:课程名称+英文空格+平时成绩平均分+英文空格+期末考试平均分+英文空格+总成绩平均分
实验课成绩格式:课程名称+英文空格+总成绩平均分
如果某门课程没有任何成绩信息,输出:课程名称+英文空格+"has no grades yet"
3)班级所有课程总成绩平均分按班级由低到高排序输出
格式:班级号+英文空格+总成绩平均分
如果某个班级没有任何成绩信息,输出:班级名称+英文空格+ "has no grades yet"
异常情况:
1)如果解析某个成绩信息时,课程名称不在已输入的课程列表中,输出:学号+英文空格+姓名+英文空格+":"+课程名称+英文空格+"does not exist"
2)如果解析某个成绩信息时,输入的成绩数量和课程的考核方式不匹配,输出:学号+英文空格+姓名+英文空格+": access mode mismatch"
以上两种情况如果同时出现,按第一种情况输出结果。
3)如果解析某个课程信息时,输入的课程性质和课程的考核方式不匹配,输出:课程名称+" : course type & access mode mismatch"
4)格式错误以及其他信息异常如成绩超出范围等,均按格式错误处理,输出"wrong format"
5)若出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
信息约束:
1)成绩平均分只取整数部分,小数部分丢弃
参考类图(与第一次相同,其余内容自行补充):
复杂度分析
类图
代码如下:
点击查看代码
import java.text.Collator;
import java.util.*;
public class Main {
public static void main(String[] args) {
HashMap<String, Course> courses = new HashMap<>();
HashMap<String, Student> students = new HashMap<>();
HashMap<String, StudentClass> classes = new HashMap<>();
ArrayList<ChooseCourse> chooseCourses = new ArrayList<>();
Scanner input = new Scanner(System.in);
String sentence = input.nextLine();
while (!sentence.equals("end")) {
if (sentence.matches("^\\S{1,10} (必修|选修|实验) (考试|考察|实验)$")) {
String[] splited = sentence.split(" ");
if (((splited[1].equals("必修") && splited[2].equals("考试")) ||
(splited[1].equals("选修") && (splited[2].equals("考试") || splited[2].equals("考察")))) ||
(splited[1].equals("实验") && splited[2].equals("实验"))) {
if (!courses.containsKey(splited[0])) {
Course course = new Course();
course.name = splited[0];
course.category = splited[1];
course.method = splited[2];
courses.put(splited[0], course);
}
} else {
System.out.println(splited[0] + " : course type & access mode mismatch");
}
} else if (sentence.matches("[0-9]{8} \\S{1,10} \\S{1,10} ([0-9]|[1-9][0-9]|100)")) {
String[] splited = sentence.split(" ");
String studentNum = splited[0];
String studentName = splited[1];
String courseName = splited[2];
int grade = Integer.parseInt(splited[3]);
if (!students.containsKey(studentNum)) {
Student student = new Student();
student.num = studentNum;
student.name = studentName;
students.put(studentNum, student);
}
Student student = students.get(studentNum);
if (!classes.containsKey(studentNum.substring(0, 6))) {
StudentClass studentClass = new StudentClass();
studentClass.classNum = studentNum.substring(0, 6);
studentClass.students = new HashMap<>();
classes.put(studentNum.substring(0, 6), studentClass);
}
classes.get(studentNum.substring(0, 6)).students.put(studentNum, student);
if (!courses.containsKey(courseName)) {
System.out.println(studentNum + " does not exist");
break;
} else {
Course course = courses.get(courseName);
if (course.method.equals("考察")) {
if (course.category.equals("必修")) {
System.out.println(studentNum + " " + studentName + " : access mode mismatch");
break;
}
ChooseCourse chooseCourse = new ChooseCourse();
chooseCourse.student = student;
chooseCourse.course = course;
CheckScore checkScore = new CheckScore();
checkScore.finalGrade = grade;
chooseCourse.score = checkScore;
chooseCourses.add(chooseCourse);
} else if (course.method.equals("考试")) {
if (course.category.equals("实验")) {
System.out.println(studentNum + " " + studentName + " : access mode mismatch");
break;
}
ChooseCourse chooseCourse = new ChooseCourse();
chooseCourse.student = student;
chooseCourse.course = course;
TestScore testScore = new TestScore();
testScore.finalGrade = grade;
chooseCourse.score = testScore;
chooseCourses.add(chooseCourse);
}
}
} else if (sentence.matches("[0-9]{8} \\S{1,10} \\S{1,10} ([0-9]|[1-9][0-9]|100) ([0-9]|[1-9][0-9]|100)")) {
String[] splited = sentence.split(" ");
String studentNum = splited[0];
String studentName = splited[1];
String courseName = splited[2];
int dailyGrade = Integer.parseInt(splited[3]);
int finalGrade = Integer.parseInt(splited[4]);
if (!students.containsKey(studentNum)) {
Student student = new Student();
student.num = studentNum;
student.name = studentName;
students.put(studentNum, student);
}
Student student = students.get(studentNum);
if (!classes.containsKey(studentNum.substring(0, 6))) {
StudentClass studentClass = new StudentClass();
studentClass.classNum = studentNum.substring(0, 6);
studentClass.students = new HashMap<>();
classes.put(studentNum.substring(0, 6), studentClass);
}
classes.get(studentNum.substring(0, 6)).students.put(studentNum, student);
if (!courses.containsKey(courseName)) {
System.out.println(studentNum + " does not exist");
break;
} else {
Course course = courses.get(courseName);
if (course.method.equals("考察")) {
System.out.println(studentNum + " " + studentName + " : access mode mismatch");
break;
} else if (course.method.equals("考试")) {
ChooseCourse chooseCourse = new ChooseCourse();
chooseCourse.student = student;
chooseCourse.course = course;
TestScore testScore = new TestScore();
testScore.dialyGrade = dailyGrade;
testScore.finalGrade = finalGrade;
chooseCourse.score = testScore;
chooseCourses.add(chooseCourse);
}
}
} else if (sentence.matches("([0-9]{8})( )(\\S{1,10})( )(\\S{1,10})( )([4-9])( )((([0-9]|[1-9][0-9]|100)( ))+)([0-9]|[1-9][0-9]|100)")) {
String[] splited = sentence.split(" ");
String studentNum = splited[0];
String studentName = splited[1];
String courseName = splited[2];
int numExperiments = Integer.parseInt(splited[3]);
List<Integer> grades = new ArrayList<>();
for (int i = 4; i < splited.length; i++) {
grades.add(Integer.parseInt(splited[i]));
}
if (!students.containsKey(studentNum)) {
Student student = new Student();
student.num = studentNum;
student.name = studentName;
students.put(studentNum, student);
}
Student student = students.get(studentNum);
if (!classes.containsKey(studentNum.substring(0, 6))) {
StudentClass studentClass = new StudentClass();
studentClass.classNum = studentNum.substring(0, 6);
studentClass.students = new HashMap<>();
classes.put(studentNum.substring(0, 6), studentClass);
}
classes.get(studentNum.substring(0, 6)).students.put(studentNum, student);
if (!courses.containsKey(courseName)) {
System.out.println(studentNum + " does not exist");
break;
} else {
Course course = courses.get(courseName);
if (!course.method.equals("实验")) {
System.out.println(studentNum + " " + studentName + " : access mode mismatch");
break;
} else if (numExperiments != grades.size()) {
System.out.println(studentNum + " " + studentName + " : access mode mismatch");
break;
} else {
ChooseCourse chooseCourse = new ChooseCourse();
chooseCourse.student = student;
chooseCourse.course = course;
ExperimentScore experimentScore = new ExperimentScore();
experimentScore.grades = grades;
chooseCourse.score = experimentScore;
chooseCourses.add(chooseCourse);
}
}
} else {
System.out.println("wrong format");
}
sentence = input.nextLine();
}
// 按照学号排序,并输出成绩
TreeMap<String, Student> sortedMap = new TreeMap<>(students);
for (Student student : sortedMap.values()) {
String num = student.num;
String name = student.name;
int allGrade = 0;
int addNum = 0;
for (ChooseCourse chooseCourse : chooseCourses) {
if (num.equals(chooseCourse.student.num)) {
allGrade += chooseCourse.score.getGrade();
addNum++;
}
}
if (addNum == 0) {
System.out.println(num + " " + name + " did not take any exams");
} else {
int averageGrade = allGrade / addNum;
System.out.println(num + " " + name + " " + averageGrade);
}
}
// 给课程排序
Comparator<String> chineseComparator = (s1, s2) -> {
Collator collator = Collator.getInstance(Locale.CHINA);
return collator.compare(s1, s2);
};
List<String> sortedKeys = new ArrayList<>(courses.keySet());
sortedKeys.sort(chineseComparator);
for (String key : sortedKeys) {
Course course = courses.get(key);
int addNum = 0;
int allGrade = 0;
int finalGrade = 0;
int dailyGrade = 0;
int addNum1 = 0;
int x = -1;
for (ChooseCourse chooseCourse : chooseCourses) {
if (key.equals(chooseCourse.course.name)) {
if (course.category.equals("必修")) {
x = 0;
allGrade += chooseCourse.score.getGrade();
if (chooseCourse.score instanceof TestScore) {
finalGrade += ((TestScore) chooseCourse.score).finalGrade;
dailyGrade += ((TestScore) chooseCourse.score).dailyGrade;
addNum++;
addNum1++;
}
}
if (course.category.equals("选修")) {
allGrade += chooseCourse.score.getGrade();
if (chooseCourse.course.method.equals("考试")) {
x = 0;
if (chooseCourse.score instanceof TestScore) {
finalGrade += ((TestScore) chooseCourse.score).finalGrade;
dailyGrade += ((TestScore) chooseCourse.score).dailyGrade;
addNum++;
addNum1++;
}
}
if (chooseCourse.course.method.equals("考察")) {
x = 2;
finalGrade += chooseCourse.score.getGrade();
addNum++;
}
}
if (chooseCourse.course.method.equals("实验")) {
x = 1;
allGrade += chooseCourse.score.getGrade();
addNum++;
}
}
}
if (x == -1) {
System.out.println(course.name + " has no grades yet");
} else if (x == 0) {
System.out.println(key + " " + dailyGrade / addNum1 + " " + finalGrade / addNum + " " + allGrade / addNum);
} else if (x == 2) {
System.out.println(key + " " + finalGrade / addNum + " " + allGrade / addNum);
} else {
System.out.println(key + " " + allGrade / addNum);
}
}
// 给班级排序
TreeMap<String, StudentClass> sortedClassMap = new TreeMap<>(classes);
for (StudentClass studentClass : sortedClassMap.values()) {
String classNum = studentClass.classNum;
int allGrade = 0;
int addNum = 0;
for (Student student : studentClass.students.values()) {
String studentNum = student.num;
for (ChooseCourse chooseCourse : chooseCourses) {
if (studentNum.equals(chooseCourse.student.num)) {
allGrade += chooseCourse.score.getGrade();
addNum++;
}
}
}
if (addNum == 0) {
System.out.println(classNum + " has no grades yet");
} else {
int averageGrade = allGrade / addNum;
System.out.println(classNum + " " + averageGrade);
}
}
}
}
class Student {
String num;
String name;
}
class StudentClass {
String classNum;
HashMap<String, Student> students;
}
class Course {
String name;
String category;
String method;
}
abstract class Score {
abstract int getGrade();
}
class TestScore extends Score {
public int dialyGrade;
int finalGrade;
int dailyGrade;
@Override
int getGrade() {
return (int) (finalGrade * 0.7 + dailyGrade * 0.3);
}
}
class CheckScore extends Score {
int finalGrade;
@Override
int getGrade() {
return finalGrade;
}
}
class ExperimentScore extends Score {
List<Integer> grades;
@Override
int getGrade() {
int sum = 0;
for (int grade : grades) {
sum += grade;
}
return sum / grades.size();
}
}
class ChooseCourse {
Student student;
Course course;
Score score;
}
因为伤病的原因我并未完成这最后一次的大题。
3.期中考试
7-4 销售步枪问题(附加题)
前亚利桑那州境内的一位步枪销售商销售密苏里州制造的步枪机(lock)、枪托(stock)和枪管(barrel)。枪机卖45美元,枪托卖30美元,枪管卖25美元。销售商每月至少要售出一支完整的步枪,且生产限额是销售商在一个月内可销售70个枪机、80个枪托和90个枪管。
根据每个月的销售情况,计算销售商的佣金(提成)算法如下:
不到(含)1000美元的部分为10%;
1000(含)~1800美元的部分为15%;
超过1800美元的部分为20%。
佣金程序生成月份销售报告,汇总销售商的销售总额和佣金。
编程要求:必须符合面向对象编程,且保证类设计的单一职责模式,使用面向过程编程判定0分。
提示:可以设置一个销售订单类。参考类图如下:
输入格式:
输入销售商每个月售出枪机、枪托、枪管的数量,可以用空格或者回车分隔。
输出格式:
分别输出销售商在该月的销售额和佣金,中间用空格分开。
输入样例1:
在这里给出一组输入。例如:
30 40 50
输出样例1:
在这里给出相应的输出。例如:
3800.00 620.00
输入样例2:
在这里给出一组输入。例如:
88 56 98
输出样例2:
在这里给出相应的输出。例如:
Wrong Format
分析如下
本题要求设计符合面向对象编程的程序,实现销售订单的计算和佣金的计算。对于输入的数据,需要进行格式检查,并判断是否超过生产限额。输出销售总额和佣金。
在这个问题中,可以使用一个销售订单类来表示销售商的销售订单,并在其中实现计算销售额和佣金的方法。该类应该具有一个构造函数来初始化销售订单的属性(即销售的枪机、枪托和枪管数量)。然后,它应该有两个公共方法:一个是计算销售额的方法,另一个是计算佣金的方法。在计算佣金时,可以根据销售额的不同范围采用不同的佣金率。
总结一下,需要完成以下步骤:
创建一个销售订单类
在销售订单类中实现计算销售额的方法
在销售订单类中实现计算佣金的方法
检查输入的格式并判断是否超过生产限额
输出销售总额和佣金
代码如下:
点击查看代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
String[] sales = input.split(" ");
int gunCount = Integer.parseInt(sales[0]);
int stockCount = Integer.parseInt(sales[1]);
int barrelCount = Integer.parseInt(sales[2]);
GunSalesman salesman = new GunSalesman(gunCount, stockCount, barrelCount);
salesman.calculateSalesAmount();
salesman.calculateCommission();
System.out.printf("%.2f %.2f", salesman.getSalesAmount(), salesman.getCommission());
}
}
class GunSalesman {
private int gunCount;
private int stockCount;
private int barrelCount;
private double salesAmount;
private double commission;
public GunSalesman(int gunCount, int stockCount, int barrelCount) {
this.gunCount = gunCount;
this.stockCount = stockCount;
this.barrelCount = barrelCount;
}
public void calculateSalesAmount() {
salesAmount = gunCount * 45 + stockCount * 30 + barrelCount * 25;
}
public void calculateCommission() {
if (salesAmount <= 1000) {
commission = salesAmount * 0.1;
} else if (salesAmount <= 1800) {
commission = 1000 * 0.1 + (salesAmount - 1000) * 0.15;
} else {
commission = 1000 * 0.1 + 800 * 0.15 + (salesAmount - 1800) * 0.2;
}
}
public double getSalesAmount() {
return salesAmount;
}
public double getCommission() {
return commission;
}
}
踩坑心得
经过这一阶段的学习与实践,我总结出了如下的问题
-
代码应该具有良好的可读性和可维护性,同时也要注意代码复杂度,避免出现过于复杂的逻辑。
-
重视输入验证和异常处理,尽可能识别并处理所有可能出现的异常情况,并给出正确的错误提示。
-
选择合适的数据结构和算法,以实现高效的数据检索和计算。
-
在编写代码时,应该考虑到程序的性能,并进行必要的优化。
-
编写全面的测试用例,以确保程序的健壮性和正确性。
-
在编写代码时,应该遵循良好的编码规范和标准,以确保代码具有一致的风格和格式。
总的来说,编写高质量的程序需要综合考虑多个因素,包括可读性、可维护性、异常处理、数据结构和算法、测试覆盖率等。只有在这些方面都做到了好,才能编写出高效、健壮且易于维护的程序。、
改进建议 -
提高代码质量:在编写代码时,应该注重代码质量,尽可能遵循良好的编程规范和标准。这包括使用有意义的变量名、编写清晰的注释和文档、避免重复代码等。
-
优化性能:如果程序处理大量数据,可以考虑对算法进行优化,或使用高效的数据结构。此外,还可以使用并行计算等技术来提高程序的性能。
-
异常处理:加强对异常情况的处理,避免程序崩溃或出现未处理的错误。同时,可以通过记录日志的方式来方便排查问题。
-
测试覆盖率:编写全面的测试用例,覆盖所有可能的情况,并通过自动化测试来确保程序的正确性和健壮性。
-
优化算法和数据结构:根据具体需求,选择合适的算法和数据结构,以提高程序的效率和性能。
-
模块化和函数抽象:通过模块化和函数抽象来减少代码复杂度,提高代码的可读性和可维护性。
总之,改进一个程序需要考虑多个方面,包括代码质量、性能优化、用户交互性、异常处理、测试覆盖率等。通过不断优化和改进,可以让程序更加健壮和高效。