一、前言
本次博客主要涉及到成绩统计系统、HashMap容器的检索、排序等基本实现、以及期末测试的三棱锥表面积和体积的计算。
知识点包括面向对象的设计思想、集合类的使用、异常处理、字符串处理、输入输出流以及Java语言基础等。
面向对象的基础知识:包括类和对象的基础概念、构造方法、访问权限和成员变量
同时,代码中还涉及到了数据结构的遍历和操作,以及对数据进行统计和计算的逻辑实现,哈希表的基本知识,基础的控制流和数据结构:例如循环、条件语句、数组和列表。
7-1 容器-ArrayList-排序:学习新容器ArrayList并应用其进行排序。
7-2 课程成绩统计程序-3:应用7-1对课程成绩统计程序进行优化。
7-3 jmu-Java-02基本语法-03-身份证排序:学习使用Comparator接口对目标进行排序。
7-4 jmu-Java-04面向对象进阶-03-接口-自定义接口ArrayIntegerStack:加深对该接口的学习以及应用。
7-5 jmu-Java-03面向对象基础-05-覆盖:对PersonOverride类中的一些功能进行复写
题目的难度中等偏上,适合用来考察我们对面向对象设计原则、类设计原则、类之间的继承关联等关系的处理、输入处理、异常处理、JAVA相关接口的理解,但是关于课程成绩统计程序的部分还是掌握得不够透彻,导致最终类结构设计出现了一些问题。
题量中等,但是成绩统计系统包含了一些细节和需求,包括各种异常处理和特殊情况的处理,有些异常处理情况还是没考虑到,编码速度不太够,导致期末处理报错时间过长。
7-1 容器-HashMap-检索 分数 10 作者 蔡轲 单位 南昌航空大学输入多个学生的成绩信息,包括:学号、姓名、成绩。
学号是每个学生的唯一识别号,互不相同。
姓名可能会存在重复。
使用HashMap存储学生信息,并实现根据学号的检索功能
输入格式:
输入多个学生的成绩信息,每个学生的成绩信息格式:学号+英文空格+姓名+英文空格+成绩
以“end”为输入结束标志
end之后输入某个学号,执行程序输出该生的详细信息
输出格式:
输出查询到的学生信息格式:学号+英文空格+姓名+英文空格+成绩
如果没有查询到,则输出:"The student "+查询的学号+" does not exist"
输入样例1:
在这里给出一组输入。例如:
20201107 张少军 83
20201116 李四 78
20201118 郑觉先 80
end
20201116
输出样例1:
在这里给出相应的输出。例如:
20201116 李四 78
输入样例2:
在这里给出一组输入。例如:
20201107 张少军 83
20201116 李四 78
20201118 郑觉先 80
end
20202316
输出样例2:
在这里给出相应的输出。例如:
The student 20202316 does not exist
import java.util.Scanner; import java.util.HashMap; public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); HashMap <String,String> stu=new HashMap<>(); String input=""; while(!input.equals("end")) { input=scanner.nextLine(); if(input.equals("end")) break; String[] a=input.split(" "); String sno=a[0]; String name=a[1]; String score=a[2]; stu.put(sno,name+" "+score); } String search1=scanner.nextLine(); if(stu.containsKey(search1)) { System.out.print(search1+" "+stu.get(search1)); } else System.out.println("The student "+search1+" does not exist"); } }
containsKey
方法检查HashMap
中是否存在与搜索学号匹配的键
用HashMap
存储学生信息,键值对的形式方便查找和存储
- 创建一个
Scanner
对象,用于读取用户输入。 - 创建一个
HashMap
对象,用于存储学生信息。键是学号(sno),值是姓名和分数的组合。 - 声明一个字符串变量
input
,用于存储用户输入的每一行。 - 使用循环,读取用户输入的每一行,直到用户输入"end"为止。
- 根据空格将输入行分割为学号、姓名和分数,并将其存储到对应的变量中。
- 将学号作为键,姓名和分数的组合作为值,存储到
HashMap
中
输入多个学生的成绩信息,包括:学号、姓名、成绩。
学号是每个学生的唯一识别号,互不相同。
姓名可能会存在重复。
要求:使用HashMap存储学生信息。
输入格式:
输入多个学生的成绩信息,每个学生的成绩信息格式:学号+英文空格+姓名+英文空格+成绩
以“end”为输入结束标志
输出格式:
按学号从大到小的顺序输出所有学生信息,每个学生信息的输出格式:学号+英文空格+姓名+英文空格+成绩
import java.util.Scanner; import java.util.HashMap; import java.util.List; import java.util.TreeMap; public class Main { public static void main(String[] args) { Scanner scanner=new Scanner(System.in); TreeMap <String,String> stu=new TreeMap<>((s1,s2)->s2.compareTo(s1)); String input=""; while(!input.equals("end")) { input=scanner.nextLine(); if(input.equals("end")) break; String[] a=input.split(" "); String sno=a[0]; String name=a[1]; String score=a[2]; stu.put(sno,name+" "+score); } for(String Key:stu.keySet() ) System.out.println(Key+" "+stu.get(Key)); } }
值得注意的点是:
使用TreeMap
存储学生信息,键值对的形式方便查找和存储,使用Lambda表达式作为参数,对TreeMap
进行构造,并且实现按照学号倒序存储学生信息并且使用for-each
循环遍历TreeMap
中的每个键值对,将键(学号)和值(姓名和分数的组合)分别输出,以实现按照学号倒序输出学生信息
具体执行过程,在main
方法中:
创建一个Scanner
对象,用于读取用户输入。创建TreeMap
对象用于存储学生信息,声明一个字符串变量input
,用于存储用户输入的每一行。
使用循环,读取用户输入的每一行,直到用户输入"end"为止。
根据空格将输入行分割为学号、姓名和分数,并将其存储到对应的变量中,将学号作为键,姓名和分数的组合作为值,存储到TreeMap
中
课程成绩统计程序-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.lang.Character.Subset; import java.text.Collator; import java.util.*; import java.util.Map.Entry; public class Main { public static void main(String[] args) { Data data = new Data(); Judge judge = new Judge(); Output output = new Output(); Input in =new Input(); Calculate calculate = new Calculate(); Scanner input = new Scanner(System.in); String input_data; input_data=input.nextLine(); while(!input_data.equals("end")) { in.judgeInput(input_data,data); input_data=input.nextLine(); } judge.judge_courseHasGrades(data);//判断课程是否有成绩信息 judge.judge_studentHasGrades(data);//判断学生是否有成绩信息 judge.judge_classHasGrades(data);//判断班级是否有成绩信息 //打印结果 output.show(data); } } class Student1 { String sno; String name; public String Getsno() { return sno; } public String Getname() { return name; } } abstract class Score1 { int finalscore=0; int endterm=0; int normal=0; int score=0; public void setnormal(int normal) { this.normal=normal; } public void setendterm(int endterm) { this.endterm=endterm; } public abstract int Finalscore(int normal,int endterm); } class Testscore1 extends Score1 { public int Finalscore(int normal,int endterm) { finalscore=(int) Math.round(normal*0.3+endterm*0.7); return finalscore; } } class Chascore1 extends Score1 { public int Finalscore(int normal,int endterm) { return endterm; } } class Classroom1 { } class Course1 { String coursekind; String cname; String testtype; } class Select1 { Course course=new Course(); Student student=new Student(); Score1 testscore=new Testscore1(); Score1 chascore=new Chascore1(); } /*要算 学生的所有课程平均成绩、各科平均分、班级各科总成绩的平均分 */ class Student { String number;//学号 String studentName;//姓名 String classNumber;//班级 boolean hasGrades = false; ArrayList<StudentCourseGrades> gradesList = new ArrayList<StudentCourseGrades>();//学生成绩列表 Student() { } Student(String number, String studentName) { this.number = number; this.studentName = studentName; getClassNumber(number);//获取学生班级 } void getClassNumber(String number)//获取学生班级 { classNumber = number.substring(0, 6); } int sum_grade = 0;//该学生所有课程平均成绩—————遍历studentMap,累加所有科目最终成绩,计算平均分 void getSumGrade()//计算该学生所有课程平均成绩 { sum_grade = 0; int t = 0; for(int i = 0; i<gradesList.size();i++) { sum_grade += gradesList.get(i).Aend_grade; } if(gradesList.size()!=0) sum_grade = sum_grade/gradesList.size(); } } class Course { String courseName;//课程名称 String nature;//课程性质 String way;//考核方式 boolean hasGrades = false; Course() { } } //课程关联班级 class bx_Course extends Course { bx_Course(String courseName, String nature, String way) { this.courseName = courseName; this.nature = nature; this.way = way; } } class xx_Course extends Course { xx_Course(String courseName, String nature, String way) { this.courseName = courseName; this.nature = nature; this.way = way; } void add(String nature) { this.nature = nature; } } class sy_Course extends Course { sy_Course(String courseName, String nature, String way) { this.courseName = courseName; this.nature = nature; this.way = way; } } class SelectCourse { Student student; Course course; StudentCourseGrades studentGrades; void addStudent(String studentNumber, String name, Data data) {// 添加学生信息 if (!data.mp_student.containsKey(studentNumber)) { student = new Student(studentNumber, name); data.mp_student.put(studentNumber, student); // 学生加入对应班级 Bclass bclass = new Bclass(); bclass.addBclass(student, data.mp_bclass); } } void addCourse(String courseName, String nature, String way, Data data) {// 添加课程信息 if (nature.equals("必修")) { course = new bx_Course(courseName, nature, "考试"); } else if (nature.equals("选修")) { course = new xx_Course(courseName, nature, way); } else if (nature.equals("实验")) { course = new sy_Course(courseName, nature, way); } if (!data.mp_course.containsKey(courseName)) { data.mp_course.put(courseName, course); } } void addGrades(String[] arr, int normal_grade, int last_grade, Course course, Student student, Data data) {// 多态添加课程成绩 data.mp_student.forEach((key, value) -> { if (key.equals(arr[0])) { if (course.way.equals("考试")) {// 必修课只能为考试课 studentGrades = new ks_Course(course.courseName, normal_grade, last_grade); } else if (course.way.equals("考察")) {// 选修课为考察课或者考试课 studentGrades = new kc_Course(course.courseName, last_grade); } else if (course.way.equals("实验")) { studentGrades = new sy_Course0(course.courseName, arr); } value.gradesList.add(studentGrades); } }); } } class StudentCourseGrades//学生的课程成绩 { String bclassName;//学生课程名称 int normal_grade;//平时成绩 int last_grade;//期末成绩 int Aend_grade;//最终成绩 StudentCourseGrades(){ } void getEndGrade()//计算总成绩 { } } class kc_Course extends StudentCourseGrades//考察课 { kc_Course(String bclassName, int last_grade) { this.bclassName = bclassName; this.last_grade = last_grade; getEndGrade(); } void getEndGrade() { Aend_grade = last_grade; } } class ks_Course extends StudentCourseGrades//考试课 { ks_Course(String bclassName, int normal_grade, int last_grade){ this.bclassName = bclassName; this.normal_grade = normal_grade; this.last_grade = last_grade; getEndGrade(); } void getEndGrade() { Aend_grade = (int)(normal_grade*0.3+last_grade*0.7); } } class sy_Course0 extends StudentCourseGrades//实验课 { sy_Course0(String bclassName, String[] arr) { this.bclassName = bclassName; getEndGrade(arr); } void getEndGrade(String[] arr) { int sum = 0; for(int i = 4; i < arr.length; i++) { sum += Integer.parseInt(arr[i]); } Aend_grade = sum/(arr.length-4); } } class Bclass { ArrayList<Student> list = new ArrayList<Student>(); // 学生列表 boolean hasGrades = false; // 记录班级是否有成绩信息 int sum_grades = 0; boolean findBclass(String classNumber, Map<String, Bclass> mp_bclass) {// 查找班级 return mp_bclass.containsKey(classNumber); } void addBclass(Student student, Map<String, Bclass> mp_bclass) {// 学生加入班级 String classNumber = student.classNumber; Bclass bclass = mp_bclass.getOrDefault(classNumber, new Bclass()); bclass.list.add(student); mp_bclass.put(classNumber, bclass); } void getSumGrade() {// 计算该班级所有课程平均成绩 int t = 0; for (int i = 0; i < list.size(); i++) { sum_grades += list.get(i).sum_grade; if (list.get(i).sum_grade != 0) { t++; } } if (t != 0) { sum_grades = (int) (sum_grades / t); } } } class Data { // 用map存储学生信息,String键是学号,value为Student Map<String, Student> mp_student = new TreeMap<>(new Comparator<String>() { public int compare(String o1, String o2) { return o1.compareTo(o2); } }); // 存储输入的班级信息 Map<String, Bclass> mp_bclass = new TreeMap<>(new Comparator<String>() { public int compare(String o1, String o2) { return o1.compareTo(o2); } }); // 按课程名称进行字典序排序 Map<String, Course> mp_course = new TreeMap<>(Collator.getInstance(Locale.CHINA)); ArrayList<SelectCourse> list = new ArrayList<SelectCourse>();//选课列表 } class Input { boolean falg=true;//补丁 void judgeInput(String input_data, Data data) { Judge judge = new Judge(); SelectCourse select = new SelectCourse(); boolean okNumber, okStudentName, okCourseName; String[] arr=input_data.split(" ");//按一个或两个空格分隔 int len = arr.length; String way=""; int mood = judge.judge_mood(len); if(mood == 1)//输入课程信息 { if(len==2) way="考试"; else way=arr[2]; if(judge.judge_courseNameNature(arr[0], arr[1]) == false)//判断课程名称和课程性质是否合法 { System.out.println("wrong format"); return ; } else { if(judge.judge_courseNatureWay(arr[1], way) != 0)//判断课程名称是否在已输入的课程列表中 { if(judge.judge_courseNatureWay(arr[1], way) == 1) { System.out.println(arr[0]+" : course type & access mode mismatch"); return ; } else//x = -1 { System.out.println("wrong format"); return ; } } else select.addCourse(arr[0], arr[1], way, data); } } else if(mood == 2)//输入课程成绩信息 { int normal_grade = 0, last_grade = 0; if(len == 5) { if(!arr[3].matches("^(100|[0-9]{1,2})$") || !arr[4].matches("^(100|[0-9]{1,2})$")) { System.out.println("wrong format"); return ; } normal_grade = Integer.parseInt(arr[3]); last_grade = Integer.parseInt(arr[4]); } else { if(!arr[3].matches("^(100|[0-9]{1,2})$")) { System.out.println("wrong format"); return ; } last_grade = Integer.parseInt(arr[3]); } if((normal_grade>100||normal_grade<0) || (last_grade>100||last_grade<0)) { System.out.println("wrong format"); return; } if(judge.judge_number(arr[0]) == false||judge.judge_studentName(arr[1]) == false)//判断学号,姓名是否合法 { System.out.println("wrong format"); return ; } if(judge.judge_courseExit(arr[2], data) == false)//判断课程名称是否在已输入的课程列表中 { if(judge.judge_illege_way(arr, len, data) == -1) { System.out.println("wrong format"); return ; } System.out.println(arr[2]+" does not exist"); select.addStudent(arr[0], arr[1], data);//添加学生信息,同时将学生添加到对应班级 return ; } else if(judge.judge_illege_way(arr, len, data) != 0)//判断输入信息的成绩数量是否考核方式匹配 { //0表示成绩数量与考核方式匹配匹配,1表示不匹配,-1表示输出wrong' format if(judge.judge_illege_way(arr, len, data) == -1) { System.out.println("wrong format"); return ; } else { System.out.println(arr[0]+" "+arr[1]+" : access mode mismatch"); select.addStudent(arr[0], arr[1], data);//添加学生信息,同时将学生添加到对应班级 return ; } } else select.addStudent(arr[0], arr[1], data);//添加学生信息,同时将学生添加到对应班级 Course course = new Course(); Set<Entry<String,Course>> entrySet = data.mp_course.entrySet(); for(Map.Entry<String,Course> entry : entrySet){ if(entry.getKey().equals(arr[2])) { course = entry.getValue(); break; } } falg=false;//初始化 if(data.mp_student.containsKey(arr[0])) { for(StudentCourseGrades it:((Student)(data.mp_student.get(arr[0]))).gradesList) { if(it.bclassName.equals(arr[2])) { falg = true;//找到了 } } } if(!falg) select.addGrades(arr, normal_grade, last_grade, course, select.student, data); //添加学生成绩信息 addSelectCourse(data, arr);//添加选课列表, } else System.out.println("wrong format"); } int normal_grade = 0, last_grade = 0; void addSelectCourse(Data data, String[] arr) //添加选课列表 { SelectCourse select = new SelectCourse(); select.student = new Student(arr[0], arr[1]); String nature = "", way = ""; if(arr.length == 5) { normal_grade = Integer.parseInt(arr[3]); last_grade = Integer.parseInt(arr[4]); } else { last_grade = Integer.parseInt(arr[3]); } data.mp_course.forEach((key,value)-> { if(key.equals(arr[2])) { if(value.nature.equals("必修")) { select.course = new bx_Course(arr[2], value.nature, value.way); select.studentGrades = new ks_Course(value.courseName, normal_grade, last_grade); } else { select.course = new xx_Course(arr[2], value.nature, value.way); select.studentGrades = new kc_Course(value.courseName, last_grade); } } }); if(!falg) data.list.add(select); } } class Judge1 { private static final int MOOD_1 = 1; private static final int MOOD_2 = 2; static int judgeMood(int len) { if (len == 3 || len == 2) { return MOOD_1; } else if ((len == 5 || len == 4) || (len >= 7 && len <= 13)) { return MOOD_2; } return 0; } static boolean isNumberValid(String number) {//判断学号是否合法 return number.length() == 8; } static boolean isStudentNameValid(String name) {//判断学生姓名是否合法 return name.length() <= 10; } static boolean isCourseNameNatureValid(String name, String nature) {//判断课程名称是否合法 int len = name.length(); return len <= 10 && ("必修".equals(nature) || "选修".equals(nature) || "实验".equals(nature)); } static int judgeCourseNatureWay(String nature, String way) {//判断课程类型与考核类型是否匹配 int x = 1; if (("必修".equals(nature) && "考试".equals(way)) || ("选修".equals(nature) && ("考察".equals(way) || "考试".equals(way))) || ("实验".equals(nature) && "实验".equals(way))) { x = 0; } else if (("必修".equals(nature) && "考察".equals(way)) || ("必修".equals(nature) && "实验".equals(way)) || ("选修".equals(nature) && "实验".equals(way)) || ("实验".equals(nature) && ("考试".equals(way) || "考察".equals(way)))) { x = 1; } else { x = -1; } return x; } static boolean isCourseExist(String courseName, Data data) {//判断课程名称是否在已输入的课程列表 for (String key : data.mp_course.keySet()) { if (key.equals(courseName)) { return true; } } return false; } static int judgeIllegalWay(String[] arr, int len, Data data) {//判断输入信息的成绩数量是否考核方式匹配 if (len > 5 && (Integer.parseInt(arr[3]) < 4 || Integer.parseInt(arr[3]) > 9)) { return -1; } for (int i = 4; i < len; i++) { if (Integer.parseInt(arr[i]) < 0 || Integer.parseInt(arr[i]) > 100) { return -1; } } String way = ""; String nature = ""; if (("考试".equals(way) && len == 5) || ("必修".equals(nature) && len == 2)) { return 0; } else if (("考试".equals(way) && len != 5) || ("考察".equals(way) && len != 4)) { return 1; } else if ("考察".equals(way) && len == 4) { return 0; } else { if (Integer.parseInt(arr[3]) < 4) { return -1; } else if (len - 4 != Integer.parseInt(arr[3])) { return 1; } else { return 0; } } } static void judgeCourseHasGrades(Data data) {//判断课程是否有成绩信息 for (Map.Entry<String, Course> entry : data.mp_course.entrySet()) { String key = entry.getKey(); Course value = entry.getValue(); for (;;) { String courseName = "1"; if (key.equals(courseName)) { break; } } } } } class Calculate { int average_test_grade = 0;//该课程期末成绩平均分 int average_normal_grade = 0;//该课程平时成绩平均分 int average_end_grade = 0;//该课程总成绩平均分 int x=0;//选该课程人数 void calculate_student(Data data) { //计算学生成绩 data.mp_student.forEach((key,value)-> { value.getSumGrade(); }); } void calculate_class(Data data) { //计算班级成绩 data.mp_bclass.forEach((key,value)-> { value.getSumGrade(); }); } void calculate_course(Data data) { data.mp_course.forEach((key,value)-> { average_test_grade = 0;//该课程期末成绩平均分 average_normal_grade = 0;//该课程平时成绩平均分 average_end_grade = 0;//该课程总成绩平均分 x=0; if(value.hasGrades == false) System.out.println(key+" has no grades yet"); else { data.mp_student.forEach((key1,value1)-> { for(int i= 0 ;i<value1.gradesList.size(); i++) { if(value1.gradesList.get(i).bclassName.equals(key)) { average_test_grade += value1.gradesList.get(i).last_grade; average_normal_grade += value1.gradesList.get(i).normal_grade; average_end_grade += value1.gradesList.get(i).Aend_grade; x++; break; } } }); if(data.mp_student.size()!=0) average_test_grade = average_test_grade/x; if(data.mp_student.size()!=0) average_normal_grade = average_normal_grade/x; if(data.mp_student.size()!=0) average_end_grade = average_end_grade/x; if(value.getClass().getSimpleName().equals("bx_Course")) System.out.println(key+" "+average_normal_grade+" "+average_test_grade+" "+average_end_grade); else { if(value.way.equals("考试")) System.out.println(key+" "+average_normal_grade+" "+average_test_grade+" "+average_end_grade); else if(value.way.equals("考察")) System.out.println(key+" "+average_test_grade+" "+average_end_grade); else System.out.println(key+" "+average_end_grade); } } }); } } class Judge { static int judge_mood(int len) { int mood = 0; if(len == 3||len==2) mood = 1; else if((len == 5||len == 4) || (len >= 7&&len <= 13)) mood = 2; return mood; } static boolean judge_number(String number)//判断学号是否合法 { return number.length() == 8; } static boolean judge_studentName(String name)//判断学生姓名是否合法 { return name.length() <= 10; } static boolean judge_courseNameNature(String name, String nature)//判断课程名称是否合法 { int len = name.length(); return len <= 10 && ("必修".equals(nature) || "选修".equals(nature) || "实验".equals(nature)); } static boolean judge_courseExit(String courseName,Data data)//判断课程名称是否在已输入的课程列表 { flag = false; data.mp_course.forEach((key,value)-> { if(key.equals(courseName)) { flag = true; } }); return flag; } static int judge_courseNatureWay(String nature,String way)//判断课程类型与考核类型是否匹配 { int x = 1; if( (nature.equals("必修")&&way.equals("考试")) || (nature.equals("选修")&&(way.equals("考察")||way.equals("考试"))) || (nature.equals("实验")&&way.equals("实验"))) x = 0; else if((nature.equals("必修")&&way.equals("考察")) || (nature.equals("必修")&&way.equals("实验")) || (nature.equals("选修")&&way.equals("实验")) || (nature.equals("实验")&&(way.equals("考试")||way.equals("考察")))) x = 1; else x = -1; return x; } static boolean flag = false; static String way ="", nature = ""; static int judge_illege_way(String[] arr, int len, Data data)//判断输入信息的成绩数量是否考核方式匹配 { if(len>5) if(Integer.parseInt(arr[3]) < 4 || Integer.parseInt(arr[3])>9) return -1; for(int i=4;i<len;i++) { if(Integer.parseInt(arr[i])<0 || Integer.parseInt(arr[i])>100) return -1; } way =""; data.mp_course.forEach((key,value)-> { if(key.equals(arr[2])) { way = value.way; nature = value.nature; } }); if(way.equals("考试")&&(len == 5)||(nature.equals("必修")&&len == 2)) return 0; else if((way.equals("考试")&&len!=5) ||(way.equals("考察")&&len!=4)) return 1;//1或-1都不影响分数 else if(way.equals("考察")&&len == 4) return 0; else //if(way.equals("实验")) { if(Integer.parseInt(arr[3]) < 4) return -1; else if(len-4 != Integer.parseInt(arr[3])) return 1; else if(len-4 == Integer.parseInt(arr[3])) return 0; } return 1; } static void judge_courseHasGrades(Data data) { data.mp_course.forEach((key, value) -> { if (data.list.stream().anyMatch(d -> d.course.courseName.equals(key))) { value.hasGrades = true; } }); } static void judge_studentHasGrades(Data data)//判断学生是否有成绩信息 { data.mp_student.forEach((key,value)-> { if(value.gradesList.size() != 0) value.hasGrades = true; }); } static void judge_classHasGrades(Data data)//判断班级是否有成绩信息 { data.mp_bclass.forEach((key,value)-> { for (int i = 0; i < value.list.size(); i++) { if(value.list.get(i).gradesList.size() != 0) { value.hasGrades = true; break; } } }); } } class Output { void show(Data data)//怎么用getclass { Calculate calculate = new Calculate(); data.mp_student.forEach((key,value)-> { if(value.hasGrades == false)//判断学生是否有成绩信息 System.out.println(value.number+" "+value.studentName+" "+"did not take any exams"); else { calculate.calculate_student(data);//计算学生平均成绩 System.out.println(key+" "+value.studentName+" "+value.sum_grade); } }); calculate.calculate_course(data);//计算课程平均成绩,该方法完成了遍历mp_course和输出 calculate.calculate_class(data);//计算班级平均成绩 data.mp_bclass.forEach((key,value)-> { if(value.hasGrades == false)//判断学生是否有成绩信息 System.out.println(key+" has no grades yet"); else System.out.println(key+" "+value.sum_grades); }); } }
这次迭代主要在逻辑结构上进行了更改,推翻了1的类设计,重构了代码,这无疑增加了很大的更改量。在代码中,使用了Map存储学生信息、班级信息和课程信息,其中键是学号、班级名称和课程名称,学生类中包含学号、姓名、班级信息、是否有成绩信息以及成绩列表等属性,课程类中包含课程名称、性质、考核方式、是否有成绩信息等属性,成绩类包括了平时成绩、期末成绩和最终成绩,以及计算最终成绩的方法。
Student
类表示学生的信息,包括学号、姓名、班级信息和成绩列表等属性。Course
类表示课程的信息,包括课程名称、类型(必修/选修)以及考核方式等属性。Score
类表示学生在某门课程中的成绩信息,包括平时成绩、期末成绩和最终成绩等属性。
在Course
类中,通过calc_score
方法计算学生在该门课程中的最终成绩,并将其存储在Score
对象的final_score
属性中。在Score
类中,同样通过calc_final_score
方法计算学生的最终成绩。
这些类都采用了面向对象的设计思想,将相关的属性和方法封装在一起,使得代码结构清晰易懂。同时,这些类都有良好的扩展性,例如可以增加其他类型的成绩信息或者增加其他类型的课程信息。用一个单独的Input类模块负责接收用户输入的学生信息、课程信息和成绩信息,并进行判断和处理;judge模块用于对输入的信息进行合法性判断,如学号、姓名、课程名称等的合法性,以及课程类型与考核方式的匹配。calculate模块用于计算学生的平均成绩、课程平均成绩和班级平均成绩;output模块将计算得到的各项平均成绩输出到控制台。
在代码设计中,我利用多态来处理不同类型的课程成绩信息,使代码结构更清晰,易于维护,但是有些地方还不符合单一原则问题,导致后续的代码迭代出现了很大问题。
7-4 动物发声模拟器(多态) 分数 20 作者 刘凤良 单位 天津仁爱学院
设计一个动物发生模拟器,用于模拟不同动物的叫声。比如狮吼、虎啸、狗旺旺、猫喵喵……。
定义抽象类Animal,包含两个抽象方法:获取动物类别getAnimalClass()、动物叫shout();
然后基于抽象类Animal定义狗类Dog、猫类Cat和山羊Goat,用getAnimalClass()方法返回不同的动物类别(比如猫,狗,山羊),用shout()方法分别输出不同的叫声(比如喵喵、汪汪、咩咩)。
最后编写AnimalShoutTest类测试,输出:
猫的叫声:喵喵
狗的叫声:汪汪
山羊的叫声:咩咩
其中,在AnimalShoutTestMain类中,用speak(Animal animal){}方法输出动物animal的叫声,在main()方法中调用speak()方法,分别输出猫、狗和山羊对象的叫声。
import java.util.Scanner; public class Main { public static void main(String[] args) { Cat cat = new Cat(); Dog dog = new Dog(); Goat goat = new Goat(); speak(cat); speak(dog); speak(goat); } static void speak(Animal animal) { System.out.println(animal.getAnimalClass()+"的叫声:"+animal.shout()); } } //定义抽象类Animal abstract class Animal { String animaltype; public Animal(){} public abstract String getAnimalClass(); public abstract String shout(); } //基于Animal类,定义猫类Cat,并重写两个抽象方法 class Cat extends Animal { public String getAnimalClass() { return "猫"; } public String shout() { return "喵喵"; } } //基于Animal类,定义狗类Dog,并重写两个抽象方法 class Dog extends Animal { public String getAnimalClass() { return "狗"; } public String shout() { return "汪汪"; } } //基于Animal类,定义山羊类Goat,并重写两个抽象方法 class Goat extends Animal { public String getAnimalClass() { return "山羊"; } public String shout() { return "咩咩"; } }
-
抽象类(abstract class):
Animal
类就是一个抽象类,其中定义了getAnimalClass()
和shout()
两个抽象方法。 -
继承(inheritance):,
Cat
、Dog
和Goat
分别继承自Animal
类,并且重写了getAnimalClass()
和shout()
两个抽象方法。 -
多态(polymorphism):在
Main
类的speak
方法中,参数的类型是Animal
类型,但实际上可以接受任何继承自Animal
的类的实例。这就是多态的体现,通过传入不同的动物实例,调用各自的shout
方法,实现了不同动物的叫声输出
题目描述
编辑
输入多个学生的成绩信息,包括:学号、姓名、数学成绩、物理成绩。
学号是每个学生的唯一识别号,互不相同。
姓名可能会存在重复。
要求:使用ArrayList存储学生信息。
输入格式:
输入多个学生的成绩信息,每个学生的成绩信息格式:学号+英文空格+姓名+英文空格+数学成绩+英文空格+物理成绩
以“end”为输入结束标志
输出格式:
按数学/物理成绩之和从高到低的顺序输出所有学生信息,每个学生信息的输出格式:学号+英文空格+姓名+英文空格+数学/物理成绩之和
成绩相同的情况,按输入的先后顺序输出
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); List<Student> students = new ArrayList<>(); int index = 0; while (true) { String input = sc.nextLine(); if ("end".equals(input)) { break; } String[] tokens = input.split(" "); String id = tokens[0]; String name = tokens[1]; int math = Integer.parseInt(tokens[2]); int physics = Integer.parseInt(tokens[3]); Student student = new Student(id, name, math, physics,index); students.add(student); } students.sort(Comparator.comparing(Student::getSum).reversed().thenComparing(Student::getIndex)); for (Student student : students) { System.out.println(student); } } private static class Student { private final String id; private final String name; private final int math; private final int physics; private final int sum; private final int index; public Student(String id, String name, int math, int physics,int index) { this.id = id; this.name = name; this.math = math; this.physics = physics; this.sum = math + physics; this.index = index++; } public String getId() { return id; } public String getName() { return name; } public int getMath() { return math; } public int getPhysics() { return physics; } public int getSum() { return sum; } public int getIndex() { return index; } public String toString() { return id + " " + name + " " + sum; } } }
在main 方法中,使用 Scanner 对象从标准输入中读取每个学生的信息,并将它们添加到一个 List<Student> 中。然后,使用 Comparator 对象对该列表进行排序,排序规则是先按照学生的总分逆序排列,然后按照学生的输入顺序排列。最后,程序打印排序后的学生列表。
程序中还定义了一个内部类 Student,用于表示学生。有一个带参数的构造函数,用于初始化学生的各个属性,并提供了一些访问器方法(如 getId、getName、getMath、getPhysics、getSum 和 getIndex),以及一个 toString 方法,用于将学生对象转换为字符串形式
7-2 课程成绩统计程序-3 分数 64 作者 蔡轲 单位 南昌航空大学课程成绩统计程序-3在第二次的基础上修改了计算总成绩的方式,
要求:修改类结构,将成绩类的继承关系改为组合关系,成绩信息由课程成绩类和分项成绩类组成,课程成绩类组合分项成绩类,分项成绩类由成绩分值和权重两个属性构成。
完成课程成绩统计程序-2、3两次程序后,比较继承和组合关系的区别。思考一下哪一种关系运用上更灵活,更能够适应变更。
题目最后的参考类图未做修改,大家根据要求自行调整,以下内容加粗字体显示的内容为本次新增的内容。
某高校课程从性质上分为:必修课、选修课、实验课,从考核方式上分为:考试、考察、实验。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。
考察的总成绩直接等于期末成绩
实验的总成绩等于课程每次实验成绩乘以权重后累加而得。
课程权重值在录入课程信息时输入。(注意:所有分项成绩的权重之和应当等于1)
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。实验课的成绩必须为实验。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式、分项成绩数量、每个分项成绩的权重。
考试课信息格式:课程名称+英文空格+课程性质+英文空格+考核方式+英文空格+平时成绩的权重+英文空格+期末成绩的权重
考察课信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
实验课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式+英文空格+分项成绩数量n+英文空格+分项成绩1的权重+英文空格+。。。+英文空格+分项成绩n的权重
实验次数至少4次,不超过9次
课程性质输入项:必修、选修、实验
考核方式输入选项:考试、考察、实验
考试/考查课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
考试/考查课程成绩信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
实验课程成绩信息包括:学号、姓名、课程名称、每次成绩{在系列-2的基础上去掉了(实验次数),实验次数要和实验课程信息中输入的分项成绩数量保持一致}
实验课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+第一次实验成绩+...+英文空格+最后一次实验成绩
以上信息的相关约束:
1)成绩是整数,不包含小数部分,成绩的取值范围是【0,100】
2)学号由8位数字组成
3)姓名不超过10个字符
4)课程名称不超过10个字符
5)不特别输入班级信息,班级号是学号的前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)若出现重复的课程/成绩信息,只保留第一个课程信息,忽略后面输入的。
6)如果解析实验课程信息时,输入的分项成绩数量值和分项成绩权重的个数不匹配,输出:课程名称+" : number of scores does not match"
7)如果解析考试课、实验课时,分项成绩权重值的总和不等于1,输出:课程名称+" : weight value error"
信息约束:
1)成绩平均分只取整数部分,小数部分丢弃
参考类图(与第一次相同,其余内容自行补充):
本次代码有个测试点没过
7-3 jmu-Java-02基本语法-03-身份证排序 分数 9 作者 郑如滨 单位 集美大学- 输入n,然后连续输入n个身份证号。
- 然后根据输入的是sort1还是sort2,执行不同的功能。输入的不是sort1或sort2,则输出
exit
并退出。
输入sort1,将每个身份证的年月日抽取出来,按年-月-日格式组装,然后对组装后的年-月-日升序输出。
输入sort2,将所有身份证按照里面的年月日升序输出。
注意:处理输入的时候,全部使用Scanner
的nextLine()
方法,以免出错
import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = Integer.parseInt(scanner.nextLine()); List<String> idList = new ArrayList<>(); for (int i = 0; i < n; i++) { idList.add(scanner.nextLine()); } String input = scanner.nextLine(); while (!input.equals("exit")) { if (input.equals("sort1")) { sortByIdWithDate(idList); } else if (input.equals("sort2")) { sortByIdFromDate(idList); } else { System.out.println("exit"); return; } input = scanner.nextLine(); } System.out.println("exit"); } private static void sortByIdWithDate(List<String> idList) { Collections.sort(idList, new Comparator<String>() { @Override public int compare(String id1, String id2) { String date1 = id1.substring(6, 14); // 提取日期部分 String date2 = id2.substring(6, 14); return date1.compareTo(date2); } }); for (String id : idList) { String formattedDate = id.substring(6, 10) + "-" + id.substring(10, 12) + "-" + id.substring(12, 14); System.out.println(formattedDate); } } private static void sortByIdFromDate(List<String> idList) { Collections.sort(idList, new Comparator<String>() { @Override public int compare(String id1, String id2) { String date1 = id1.substring(6, 14); // 提取日期部分 String date2 = id2.substring(6, 14); return date1.compareTo(date2); } }); for (String id : idList) { System.out.println(id); } } } class Student { private final String id; private final String name; private final int math; private final int physics; private final int sum; private final int index; public Student(String id, String name, int math, int physics, int index) { this.id = id; this.name = name; this.math = math; this.physics = physics; this.sum = math + physics; this.index = index; } public String getId() { return id; } public String getName() { return name; } public int getMath() { return math; } public int getPhysics() { return physics; } public int getSum() { return sum; } public int getIndex() { return index; } @Override public String toString() { return id + " " + name + " " + sum; } public String toString1() { int top=0; StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < top; i++) { Object[] arr = null; sb.append(arr[i]); if (i != top - 1) { sb.append(", "); } } sb.append("]"); return sb.toString(); } public Integer push1(Integer item) { if (item == null) { return null; } return item; } public void sortById1() { } }
Scanner 对象读取输入的学生信息,将学生ID存储在一个 List<String> 的 idList 中。然后,根据输入的指令进行处理,如果输入为"sort1",则调用 sortByIdWithDate 方法,按照日期排序学生ID并输出;如果输入为"sort2",则调用 sortByIdFromDate 方法,按照输入顺序输出学生ID;否则,程序退出。
sortByIdWithDate 方法使用 Collections.sort 方法对 idList 进行排序,并传入一个匿名内部类作为 Comparator 对象,定义了比较规则。比较规则根据学生ID的日期部分进行比较,将日期字符串转换为日期格式后进行比较,返回比较结果。最后,按照排序后的顺序输出学生ID。
sortByIdFromDate 方法与 sortByIdWithDate 方法类似,只是没有进行排序操作,直接按照输入顺序输出学生ID
7-4 jmu-Java-04面向对象进阶-03-接口-自定义接口ArrayIntegerStack
import java.io.PrintStream; import java.util.Arrays; import java.util.Scanner; import java.util.Stack; public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int n = input.nextInt(); int m = input.nextInt(); ArrayIntegerStack stack = new ArrayIntegerStack(n); for(int i = 0 ; i < m ; i++) { int c = input.nextInt(); System.out.println(stack.push(c)); } System.out.println(stack.peek()+","+stack.empty()+","+stack.size()); System.out.println(stack); int x = input.nextInt(); for (int i = 0 ; i < x ; i++){ System.out.println(stack.pop()); } System.out.println(stack.peek()+","+stack.empty()+","+stack.size()); System.out.println(stack); } } interface IntegerStack { public Integer push(Integer item); //如果item为null,则不入栈直接返回null。如果栈满,也返回null。如果插入成功,返回item public Integer pop(); //出栈,如果为空,则返回null。出栈时只移动栈顶指针,相应位置不置为null public Integer peek(); //获得栈顶元素,如果为空,则返回null public boolean empty(); //如果为空返回true public int size(); //返回栈中元素个数 } class ArrayIntegerStack implements IntegerStack{ private Integer[] arr; private int top = 0; public ArrayIntegerStack(int n){ arr = new Integer[n]; Arrays.fill(arr, null); } public ArrayIntegerStack(){ } public String toString() { return Arrays.toString(arr); } public Integer push(Integer item) { if (item == null || arr.length == top){ return null; } arr[top++] = item; return item; } public Integer pop() { if (top == 0){ return null; } return arr[--top]; } public Integer peek() { if (top == 0){ return null; } return arr[top - 1]; } public boolean empty() { return top == 0; } public int size() { return top; } } class pk{ public Integer push1(Integer item) { if (item == null) { return null; } return item; } public void sortById1() { } public String getId() { return "false"; } public void getName() { } public int getMath() { return 2; } public int getPhysics() { return 3; } public int getSum() { return 3; } public int getIndex() { return 123; } }
流程如下:
- 在
Main
类的main
方法中,首先使用Scanner
对象读取输入的整数n
和m
。 - 根据输入的
n
创建一个ArrayIntegerStack
对象stack
,即整数栈,并设置栈的容量为n
。 - 使用循环从输入中读取
m
个整数,并依次调用stack
对象的push
方法将整数入栈,并将返回的结果打印输出。 - 调用
stack
对象的peek
、empty
和size
方法,并将结果打印输出。 - 再次使用循环从输入中读取
x
个整数,并依次调用stack
对象的pop
方法将整数出栈,并将结果打印输出。 - 再次调用
stack
对象的peek
、empty
和size
方法,并将结果打印输出。
7-5 jmu-Java-03面向对象基础-05-覆盖
import java.util.*; class PersonOverride{ private String name; private int age; private boolean gender; public String toString() { return name + "-" + age + "-" + gender; } public boolean equals(Object o){ if (this == o){ return true; } if(o == null) { return false; } if (this.getClass() != o.getClass()){ return false; } PersonOverride p = (PersonOverride)o; boolean a1 = Objects.equals((this.name), p.name); boolean a2 = (this.age == p.age); boolean a3 = (this.gender == p.gender); if(a1 && a2 && a3){ return true; } return false; } public PersonOverride(String _name, int _age, boolean _gender){ name = _name; age = _age; gender = _gender; } public PersonOverride(){ this("default",1,true); } } public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int i,count = 0; int n1 = in.nextInt(); PersonOverride[] person1 = new PersonOverride[n1]; for (i = 0; i < n1; i++) { person1[i] = new PersonOverride(); } int n2 = in.nextInt(); in.nextLine(); PersonOverride[] person2 = new PersonOverride[n2]; for (i = 0; i < n2; i++) { String str = in.nextLine(); String[] arr = str.split("\\s+"); PersonOverride temp = new PersonOverride(arr[0],Integer.parseInt(arr[1]),Boolean.valueOf(arr[2])); boolean f = true; for (int j = 0; j < n2; j++) { if(temp.equals(person2[j])){ f = false; } } if(f){ person2[i] = new PersonOverride(arr[0],Integer.parseInt(arr[1]),Boolean.valueOf(arr[2])); } } for ( i = 0; i < n1; i++) { System.out.println(person1[i]); } for (i = 0; i < n2; i++) { if(person2[i] == null){ continue; } count++; System.out.println(person2[i]); } System.out.println(count); System.out.println(Arrays.toString(PersonOverride.class.getConstructors())); } }
创建一个 Scanner
对象 in
,用于接收用户输入。读取整数 n1
,创建一个长度为 n1
的 PersonOverride
数组 person1
,并将每个元素初始化为默认构造方法创建的 PersonOverride
对象。读取整数 n2
,创建一个长度为 n2
的 PersonOverride
数组 person2
。
循环读取 n2
行输入,每行包含一个字符串表示人物的姓名、年龄和性别。将输入按空格进行分割,并使用分割后的值创建一个 PersonOverride
对象 temp
。
遍历数组 person2
,如果 temp
与任何一个已存在的对象相等,则将布尔变量 f
设置为 false。
如果 f
为 true,说明 temp
是一个新的对象,将其赋值给 person2[i]
。
遍历数组 person1
,并打印每个元素。
遍历数组 person2
,如果元素不为 null,则将计数变量 count
自增,并打印元素。
打印计数变量 count
的值。
打印 PersonOverride
类的所有构造方法。
总体来说,该代码通过输入创建了两个 PersonOverride
对象数组,并进行了比较和输出操作
期末测试:
7-1 立体图形问题 分数 10 作者 段喜龙 单位 南昌航空大学编程求得正方体和正三棱锥的表面积和体积,要求必须体现扩展性(继承)和多态性。
类结构如下图所示(参考):
import java.util.Scanner; abstract class Solid { abstract double getSurfaceArea(); abstract double getVolume(); } class Cube extends Solid { private double side; public Cube(double side) { this.side = side; } double getSurfaceArea() { return 6 * side * side; } double getVolume() { return side * side * side; } } class RegularPyramid extends Solid { private double side; public RegularPyramid(double side) { this.side = side; } double getSurfaceArea() { double baseArea = Math.sqrt(3) * side * side; return baseArea; } double getVolume() { double baseArea = side * side * Math.sqrt(3) / 4; double height = Math.sqrt(6) / 3 * side; return baseArea * height / 3; } } public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); double side = input.nextDouble(); display(new Cube(side)); display(new RegularPyramid(side)); } public static void display(Solid solid) { System.out.println(String.format("%.2f", solid.getSurfaceArea())); System.out.println(String.format("%.2f", solid.getVolume())); } }
定义了一个抽象类Solid
和两个具体的子类Cube
和RegularPyramid
。
Solid
是一个抽象类,它有两个抽象方法getSurfaceArea()
和getVolume()
,分别用于计算固体的表面积和体积。这些方法没有具体的实现,需要在子类中重写。
Cube
类继承自Solid
类,它表示一个立方体。它有一个私有变量side
表示边长,在构造函数中初始化。getSurfaceArea()
方法通过公式6 * side * side
计算出表面积,getVolume()
方法通过公式side * side * side
计算出体积。
RegularPyramid
类也继承自Solid
类,表示一个正四面体(正金字塔)。它也有一个私有变量side
表示底边边长,在构造函数中初始化。getSurfaceArea()
方法通过公式Math.sqrt(3) * side * side
计算出表面积,getVolume()
方法通过公式baseArea * height / 3
计算出体积,其中baseArea
通过公式side * side * Math.sqrt(3) / 4
计算,height
通过公式Math.sqrt(6) / 3 * side
计算。
在Main
类的main
方法中,它通过Scanner
获取用户输入的边长,并创建一个Cube
对象和一个RegularPyramid
对象,然后调用display
方法来显示它们的表面积和体积。
display
方法接受一个Solid
类型的参数,输出固体的表面积和体积。使用String.format()
方法将结果格式化为保留两位小数的字符串,并使用System.out.println()
打印出来
问题描述:本问题中的魔方有两种,一种是正方体魔方,一种是正三棱锥魔方,其中,正方体或正三棱锥魔方是由单元正方体或正三棱锥组成,单元正方体或正三棱锥的个数由阶数(即层数)决定,即魔方边长=阶数*单元边长。魔方如下图所示:
利用“立体图形”问题源码,实现如下功能:
魔方有三个属性:颜色,阶数,类型(正方体魔方、正三棱锥魔方),程序要求输出魔方的颜色、表面积和体积。参考设计类图如下所示:
import java.util.Scanner; abstract class RubikCube { protected String color; protected int layer; public RubikCube(String color, int layer) { this.color = color; this.layer = layer; } public abstract double getSurfaceArea(); public abstract double getVolume(); public String getColor() { return color; } } class Cube { protected double side; public Cube(double side) { this.side = side; } public double getSurfaceArea() { return 6 * side * side; } public double getVolume() { return side * side * side; } } class RegularPyramid { protected double side; public RegularPyramid(double side) { this.side = side; } public double getSurfaceArea(int layer) { return Math.sqrt(3) * side * side; } public double getVolume(int layer) { return (Math.sqrt(2) * side * side * side) / 12; } } class SquareCube extends RubikCube { private Cube unitCube; public SquareCube(String color, int layer, Cube unitCube) { super(color, layer); this.unitCube = unitCube; } public double getSurfaceArea() { return layer * layer * unitCube.getSurfaceArea(); } public double getVolume() { return layer * layer * layer * unitCube.getVolume(); } } class RegularPyramidCube extends RubikCube { private RegularPyramid unitPyramid; public RegularPyramidCube(String color, int layer, RegularPyramid unitPyramid) { super(color, layer); this.unitPyramid = unitPyramid; } public double getSurfaceArea() { return layer * layer * unitPyramid.getSurfaceArea(layer); } public double getVolume() { return layer * layer * layer * unitPyramid.getVolume(layer); } } public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); String color = input.next(); int layer = input.nextInt(); double side = input.nextDouble(); RubikCube cube1 = new SquareCube(color, layer, new Cube(side)); color = input.next(); layer = input.nextInt(); side = input.nextDouble(); RubikCube cube2 = new RegularPyramidCube(color, layer, new RegularPyramid(side)); display(cube1); display(cube2); } public static void display(RubikCube cube) { System.out.println(cube.getColor()); System.out.printf("%.2f\n", cube.getSurfaceArea()); System.out.printf("%.2f\n", cube.getVolume()); } }
这段代码通过类的继承和多态来模拟了魔方和其组成部分
RubikCube
是一个抽象类,表示魔方,包含颜色和层数两个属性,以及获取表面积和体积的抽象方法。同时还有一个普通方法用于获取颜色。-
Cube
类表示立方体,包含边长属性和计算表面积和体积的方法。 -
RegularPyramid
类表示正四面体,包含底边边长属性和计算表面积和体积的方法。 -
SquareCube
类继承自RubikCube
,表示由多个立方体组成的立方体,包含一个立方体对象。通过重写父类的方法来计算其表面积和体积。 -
RegularPyramidCube
类也继承自RubikCube
,表示由多个正四面体组成的立方体,包含一个正四面体对象。同样通过重写父类的方法来计算其表面积和体积。
在 Main
类的 main
方法中,首先使用 Scanner
获取用户输入的颜色、层数和边长,然后创建了一个 SquareCube
对象和一个 RegularPyramidCube
对象,并调用了 display
方法来展示它们的颜色、表面积和体积。
7-4 销售步枪问题(附加题)
import java.util.Scanner; class SalesOrder { private int gunCount; private int stockCount; private int barrelCount; public SalesOrder(int gunCount, int stockCount, int barrelCount) { this.gunCount = gunCount; this.stockCount = stockCount; this.barrelCount = barrelCount; } public double calculateTotalSales() { double gunPrice = 45.0; double stockPrice = 30.0; double barrelPrice = 25.0; double totalSales = gunCount * gunPrice + stockCount * stockPrice + barrelCount * barrelPrice; return totalSales; } public double calculateCommission() { double totalSales = calculateTotalSales(); double commission = 0.0; if (totalSales <= 1000) { commission = totalSales * 0.1; } else if (totalSales <= 1800) { commission = 1000 * 0.1 + (totalSales - 1000) * 0.15; } else { commission = 1000 * 0.1 + 800 * 0.15 + (totalSales - 1800) * 0.2; } return commission; } } public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int gunCount = input.nextInt(); int stockCount = input.nextInt(); int barrelCount = input.nextInt(); SalesOrder salesOrder = new SalesOrder(gunCount, stockCount, barrelCount); double totalSales = salesOrder.calculateTotalSales(); double commission = salesOrder.calculateCommission(); System.out.printf("%.2f %.2f\n", totalSales, commission); } }
踩坑心得:
课程成绩统计程序中类的设计不够合理:有些类的职责不够单一,比如Select1
类承担了学生、课程和成绩的关联,违反了单一职责原则。再进行代码编写之前,没有涉及好一个完整的类图,导致后续编写代码过程中有些部分出现了重叠,有些功能又没有实现,这给后续的迭代带来了很大问题。
在期末测试的立体图形问题中,没有正确使用三棱锥的面积和体积计算公式,导致最后的输出出现问题。并且在重构代码的过程中,对某些功能的划分不够清晰,导致最后输出了错误结果。
对于Comparator接口使用还不熟练底层逻辑还没弄明白。
数组越界问题:在处理输入时,需要注意数组越界的问题。例如,当解析学生信息时,需要确保课程索引在合法范围内,否则可能导致数组越界异常。
总结:
通过近段时间的练习,对类的设计逻辑方法,程序的设计原则和类的封装、继承、多态有了更为清晰的认知,同时了解了一些基本函数接口的使用和重写,明白了HashMap的一些基本应用。学会了使用流式操作和Lambda表达式来简化代码。此外,我还学到了错误处理和异常处理的重要性,以及如何编写适当的单元测试来验证代码的正确性。Java提供了丰富的类库和API,掌握常用的API对于开发各类应用程序非常重要。我学习了字符串处理、集合框架、IO操作、多线程编程等常用的API,并通过实例来加深理解和熟悉使用。此外,我也了解并学习了一些常用的开发工具和框架。例如,我使用过Eclipse和IntelliJ IDEA等集成开发环境来编写和调试Java程序,学习了使用Maven进行项目构建和依赖管理,熟悉了Spring框架的基本用法等。这些工具和框架能够提高开发效率和代码质量有效的提高了代码能力,同时能够对代码进行一定的分析与优化。同时对异常处理太try-catch有了更为清晰的了解,并且能使用它解决一些简单问题。代码的迭代,也让我明白一个好的程序,是应该符合一些基本原则的,例如开闭原则,能够更加灵活地增加新的代码功能模块。通过自己的思考和查阅相关资料,我成功地解决了一些问题并提高了对Java编程的理解能力。一步一步逐渐完善自己设计,这是个艰辛但成果很愉悦的过程,这些作业也培养了我对编程语言的学习和探索能力,老师出题可谓是用心良苦。总而言之,通过近几周的学习,我对Java相关类的编写和接口的使用有了更好地认识。
改进建议:
边讲边练是一个很好的教学方式,但是一些基础知识的讲解也可以多放在课堂上,课堂练习时间太长会导致课程知识密集程度不高,很多知识都需要课后花大量的时间学习。希望可以把迭代题目的测试点公布,有时候确实不清楚自己代码在哪出现了问题,对临界条件的判定还是不够清楚。自己课后应该花更多的时间进行学习,以应对各种知识的综合应用。可以多加些小题目代替迭代的大题目,或者直接增加小题目的作业量,达到巩固基础知识的作用。
标签:return,String,int,blog3,课程,期末,成绩,public
From: https://www.cnblogs.com/ftml/p/17891410.html