前言
知识点
(1)学习类的继承,多态和异常处理,抽象类以及接口进行程序设计
(2)使用split分隔符等对数组和字符串的处理方法
(3)字符与数字之间的转化
(4)封装数据域使得类易于维护
(5)使用引用类型定义引用变量,并通过对象引用变量访问对象
(6)使用关键字this来引用对象自身
(7)使用形参定义方法和使用实参调用方法
(8)使用calender等抽象类
(9)使用正则表达式表示特定时间或日期
(10)将日期格式化
(11)将数字四舍五入和转换类型
(12)正确使用添加类或方法实现题目要求
(13)通过逐步调试修改错误或达成要求
(14)使用接口与抽象类
(15)在做题前分析好题目画出类图并按照类图解决问题
(16)学会hashmap的使用
(17)学会list接口的使用
(18)类的封装性的注重
题量和难度分析
成绩统计一:
本次题目代码写完后为四百余行,相比菜单计价系列的近700行来说代码量是大大减少了。但代码量的减少并不意味着题目变简单,反之我认为此次的作业相比以往的题要更复杂。在做这次题目的分析时我意识到这次作业要运用到hashmap和list将学生成绩统一起来,再按照题目要求使用hashmap的方法。但我再做这次作业前从未用过所以要在网上学习,而学习新知识真的好痛苦.....所以这次题目我并没有很好完成。
成绩统计二:
有了上次的经验后我开始认真分析这次题目。这道Java题目难度属于中等,需要对Java基础语法和面向对象编程有一定了解,同时需要考虑输入输出的格式和数据约束。需要实现数据的输入和处理,包括对成绩和课程信息的解析,计算各种平均分和总成绩,以及输出各种结果。同时还要考虑异常情况的处理,如格式错误、数据范围超出、输入不匹配等。需要使用Java的流处理、字符串处理、数组和集合等基本工具和数据结构来实现。在之前的题目一上添加了实验课方向,但改编的代码使用的方法和上次相比换汤不换药,所以总体上改编力度不大。
成绩统计三:
第二次作业时我已完成成绩统计题的大致思考分析,所以在分析第三次时并无太大难度。但这次作业需要修改类结构,将成绩类的继承关系改为组合关系,成绩信息也改为由成绩课程类和分项成绩类组成,而分项成绩类又由成绩分值和权重两个属性构成。在最后统分类中也改为成绩累加模式,且统分记录需去掉小数点。如此这次作业需要注意的点增大了,难度在类的继承联系中可以体现。
设计与分析
第一次成绩统计
圈复杂度

类图

第一次成绩计价各个成绩处理板块都有相应类来实现,再使用list集合对各个学生成绩信息进行统一。但由于我对hashmap和list集合使用不明确,导致此次我并未顾忌类的封装性和独立性。编写代码时多使用面向过程的思维,圈复杂度较高,类的耦合度较低。
第二次成绩统计
圈复杂度

类图

第二次成绩计价为第一次成绩计价的延伸。在原先的必修课和选修课的基础上添加了实验课版块,但对实验课的分析与实现来说和上一次作业差不多,所以在吸取上一次做题经验后我较快完成了这次作业的修改。此次代码实现总体而言完成度较高,圈复杂度较低,类的耦合度较高。
第三次成绩统计
圈复杂度

类图

第三次成绩计价为第二次成绩计价的延伸。需要修改类之间的关系,修改类结构,将成绩类的继承关系改为组合关系,成绩信息由课程成绩类和分项成绩类组成,课程成绩类组合分项成绩类,分项成绩类由成绩分值和权重两个属性构成。必修课,选修课和实验课的成绩输入方法也要修改。由于需要修改类之间的继承关系,改为组合关系,修改量较大,我未能很好修改此次代码。使这次完成代码圈复杂度较高,类的耦合度较低。
成绩统计分析
第一次成绩统计:
题目分析:
需要根据输入的成绩信息和课程信息计算出各种平均成绩并按要求输出。定义成绩类和课程类,用于存储成绩信息和课程信息。 定义学生类和班级类,用于存储学生信息和班级信息。根据输入的成绩信息和课程信息,创建相应的成绩类和课程类对象,并将它们存储到学生类和班级类对象中。遍历所有学生,计算每个学生的总成绩平均分,并按学号从小到大排序输出。遍历所有课程,计算每个课程的平时成绩平均分、期末考试平均分和总成绩平均分,并按课程名称的字符顺序输出。遍历所有班级,计算每个班级的所有课程的总成绩平均分,并按班级号从小到大排序输出。在处理输入时,需要考虑输入格式错误、课程不存在、成绩数量不匹配、课程性质和考核方式不匹配等异常情况。
类的设计:
此题我设计的类包括课程类,用于确认输入课程的格式(名称,性质和考核方式),学生类(包括名称和学号),选择类(将学生类,课程类,年级类包含其中用于管理),年级类(包含学生和成绩),成绩类(使用继承分为考试成绩类和考核成绩类),管理类(使用list集合将学生信息,成绩信息,班级信息集合管理,以便按题目要求进行输出)
代码实现:
输入信息按空格进行分割,按长度判断输入是课程信息还是学生信息。再通过空格数判断输入信息是否符合题目要求。开辟学生集合和成绩集合,按不同情况进行输入处理。其中,checkcf方法接收一个HashMap<String, Course>类型的map和一个字符串name,通过遍历map的entrySet,如果map中存在键名等于name的键值对,则返回true,否则返回false。sortHashMap方法接收一个HashMap<Integer, Student>类型的map,将map中的entry集合转换为List集合,并使用Collections类中的sort方法对List集合中的元素进行排序,排序规则为按学号升序排序。然后创建一个LinkedHashMap集合,并将List集合中的键值对存入LinkedHashMap中,最终返回LinkedHashMap集合。checkclass方法接收一个字符串arr和一个ArrayList<Classroom>类型的classroomlist,通过遍历classroomlist,如果其中存在班号等于arr转换为整数后的数值的班级,则返回该班级,否则返回null。checkcourse方法接收一个字符串arr和一个HashMap<String, Course>类型的cmap,如果cmap中存在键名等于arr的键值对,则返回该键值对的值,否则返回null。checkint方法接收一个字符串arr,判断其是否为正整数,如果是,则返回true,否则返回false。kongge方法接收一个字符串data,统计其中空格的数量,并返回该数量。input方法接收一个字符串数组arr、一个HashMap<String, Course>类型的cmap、一个整型konggenum,根据输入的不同格式,判断输入的信息类型,如果是课程信息选修或必修,则返回1;如果是成绩信息,则返回2;如果格式错误或其他信息异常,则返回0。
第二次成绩统计:
题目分析:
在第一次成绩统计题上添加了实验课。实验的总成绩等于课程每次实验成绩的平均分,且若实验课成绩不为实验则按错误格式输出。所以成绩,课程,年级统计等输入都要在第一题基础上添加实验课版块。最后输出再添加上实验课成绩输出。
类的实现:
此题我设计的类包括课程类,用于确认输入课程的格式(名称,性质和考核方式),学生类(包括名称和学号),选择类(将学生类,课程类,年级类包含其中用于管理),年级类(包含学生和成绩),成绩类(使用继承分为考试成绩类和考核成绩类),管理类(使用list集合将学生信息,成绩信息,班级信息集合管理,以便按题目要求进行输出),其中成绩类新添加实验课成绩类。
代码实现:
此代码包含了对学生、课程和班级的成绩统计和输出的过程。
首先,该代码段定义了一个 `Map` 对象 `studentCollect`,用于存储每个学生的成绩列表。然后,它遍历课程选择列表 `courseSelections`,将学生的成绩加入到相应的列表中。接下来定义一个 `Map` 对象 `studentInfo`,用于存储每个学生的成绩信息。它遍历 `studentCollect` 对象,将每个学生的成绩列表中的平均分数计算出来,并存储到 `studentInfo` 中。然后定义一个字符串列表 `studentList`,用于存储按照学生 ID 和姓名排序后的学生列表。通过调用 `Collections.sort` 方法,对 `studentList` 进行排序。输出每个学生的 ID、姓名和成绩信息。定义两个 `Map` 对象 `courseCollect` 和 `courseCollect2`,用于分别存储课程的成绩列表和考试成绩列表。它遍历 `courseSelections` 列表,并将每个课程的成绩加入到相应的列表中。定义一个 `Map` 对象 `courseInfo`,用于存储每个程的成绩信息。它遍历 `courseCollect` 和 `courseCollect2` 对象,将每个课程的平均分数计算出来,并存储到 `courseInfo` 中。代码段还使用 `courses` 对象来确定每个课程的考试方式,并将不同的平均分数格式化为不同的字符串。定义一个字符串列表 `courseList`,用于存储按照课程名称排序后的课程列表。通过调用 `Collections.sort` 方法,对 `courseList` 进行排序。最后, 输出每个课程的名称和成绩信息。定义一个 `Map` 对象 `classCollect`,用于存储每个班级的成绩列表。它遍历 `courseSelections` 列表,并将每个学生的成绩加入到相应的列表中。定义一个 `Map` 对象 `classInfo`,用于存储每个班级的成绩信息。它遍历 `classCollect` 对象,将每个班级的成绩列表中的平均分数计算出来,并存储到 `classInfo` 中。定义一个字符串列表 `classList`,用于存储按照班级名称排序后的班级列表。通过调用 `Collections.sort` 方法,对 `classList` 进行排序。最后,代码段使用 `System.out.println` 输出每个班级的名称和成绩信息。通过遍历课程选择列表来统计和输出学生、课程和班级的成绩信息。
第三次成绩统计:
题目分析:
这道题主要是涉及到输入输出格式的解析和数据运算,需要考虑多种异常情况。需要定义一些类,包括Course类、Exam类、Score类等,分别用来存储课程信息、考试信息、成绩信息等。需要解析输入信息,将它们存储到对应的类中,同时进行一些数据验证,例如权重之和是否等于1、成绩是否在有效范围等。需要根据输入的数据计算出各种平均分,并按照要求进行排序和输出。这里需要注意保留小数位,以及一些特殊情况的处理,例如某个学生没有任何成绩信息、某门课程没有任何成绩信息等。还需要处理一些异常情况,例如输入格式错误、课程名称不在已输入的课程列表中、输入的成绩数量和课程的考核方式不匹配等。这些异常情况需要在输出结果中进行提示,以便用户进行修正。
总的来说,这道题需要综合考虑输入输出格式、数据运算、异常处理等多个方面,需要仔细理解题目要求和数据约束,才能够顺利地完成编程任务。
类的实现:
在第二次成绩统计题上添加单次成绩统计类,并在管理类中添加成绩累加类,以便在最后进行累加输出。其中添加权重管理,为避免四舍五入误差,计算单个成绩时,分项成绩乘以权重后要保留小数位,计算总成绩时,累加所有分项成绩的权重分以后,再去掉小数位。学生总成绩/整个班/课程平均分的计算方法为累加所有符合条件的单个成绩,最后除以总数。
代码实现:
这段Java代码主要用于对成绩数据进行处理和展示。定义了一个Map类型的courseInfo,用于保存每门课程的成绩信息。然后用一个for循环遍历courseCollect中的数据,找到每门课程对应的成绩数据,并根据不同的考试方式进行不同的处理。如果该门课程没有成绩数据,则将"has no grades yet"存入courseInfo中;否则,如果该门课程的考试方式为"考察",则将平均分数和中位数存入courseInfo中;如果该门课程的考试方式为"实验",则将平均分数存入courseInfo中。定义了一个List类型的courseList,用于保存已有成绩的课程列表。遍历courses中的数据,并根据是否有成绩数据来决定是否将该门课程加入courseList中。然后将courseList按字母顺序排序,并遍历courseList,输出每门课程对应的成绩信息。之后该代码定义了一个Map类型的classCollect,用于保存每个班级的成绩数据。遍历courseSelections中的数据,根据学生的学号来确定班级,然后将成绩数据存入classCollect中。最后定义了一个Map类型的classInfo,用于保存每个班级的平均分数。遍历classCollect中的数据,找到每个班级对应的成绩数据,并将平均分数存入classInfo中。定义一个List类型的classList,将classInfo中的键值对(即班级和成绩)存入classList中并按照字母顺序排序。最后遍历classList,输出每个班级对应的平均分数。
踩坑心得
一.未四舍五入导致结果不符
void getgrade() { daily=this.dailygrade/10; finaly=this.finalgrade/10; daily*=3; finaly*=7; this.sumgrade=daily+finaly; }
运行结果
20201103 张三 38
java 20 40 38
202011 38
改进
void getgrade() { double daily=(double)this.dailygrade/10; double finaly=(double)this.finalgrade/10; daily*=3; finaly*=7; this.sumgrade=(int)daily+(int)finaly; }
运行结果
20201103 张三 34
java 20 40 34
202011 34
二.输出错误结果格式不正确
{ if(arr.length==3&&arr[1].equals("必修")) System.out.println(arr[0]+" : course type & access mode mismatch"); else { if(!Jugde.checkcf(cmap,arr[0])) { if(arr.length==3) cmap.put(arr[0],new Course(arr[0],arr[1],arr[2])); else cmap.put(arr[0],new Course(arr[0],arr[1],"考试")); } } break;
运行结果
数据结构 has no grades yet
形式与政治 has no grades yet
改正代码
case 1://加课程信息 { if(arr.length==3&&arr[1].equals("必修")&&arr[2].equals("考察")) System.out.println(arr[0]+" : course type & access mode mismatch"); else if(arr.length==2&&arr[1].equals("选修")) System.out.println(arr[0]+" : course type & access mode mismatch"); else { if(!Jugde.checkcf(cmap,arr[0])) { if(arr.length==3) cmap.put(arr[0],new Course(arr[0],arr[1],arr[2])); else cmap.put(arr[0],new Course(arr[0],arr[1],"考试")); } } break;
运行结果
20201103 张三 : access mode mismatch 20201103 张三 did not take any exams java has no grades yet 202011 has no grades yet
三.list集合使用不正确
List<Entry<String,Course>> clist=new ArrayList<>(cmap.entrySet());//对课程排序 Collections.sort(clist,new Comparator<Entry<int,Course>>(){ @Override public int compare(Entry<String, Course> o1, Entry<int, Course> o2) { // TODO Auto-generated method stub Collator instance=Collator.getInstance(Locale.CHINA); return instance.compare(o1.getKey(),o2.getKey()); } });
运行结果:报错
改正代码
List<Entry<String,Course>> clist=new ArrayList<>(cmap.entrySet());//对课程排序 Collections.sort(clist,new Comparator<Entry<String,Course>>(){ @Override public int compare(Entry<String, Course> o1, Entry<String, Course> o2) { // TODO Auto-generated method stub Collator instance=Collator.getInstance(Locale.CHINA); return instance.compare(o1.getKey(),o2.getKey()); } });
主要困难与改进
主要困难:
在做题中为了求快选择边做边思考下一步,忽略了代码的连贯性,常常在完成一个要求后无法完成下一个要求。比如在第一次成绩统计中一开始将成绩作为属性加在学生类中,结果无法完成取平均值输出成绩。在仔细研究题目过后才发现将成绩作为类来实现操作,代码完成度会更高。还有没有多尝试在网上搜索需要的方法完成要求,例如在第二次成绩统计中表达范围内的日期我花了几个小时都没有表达成功,而用正则表达式则很快解决了这个问题。在选择代码的实现方法上没多多参考老师的要求,比如在此次期中考试最后一题中我花费了很长时间,但如果参考老师给出的接口设计就可以很快理清代码的思绪。
改进:
在之后的作业中,在写代码前先仔细分析题目要求并画好类图,写出对应的方法和属性。在遇到各类要求譬如格式化,范围估计时多搜索资料,会有详尽的代码帮助实现。善于参考老师给出的要求和类图,有助于理解作业的方向和代码的实现。
总结
这三次作业难度较大,代码量巨大。但在前两次作业基础上,只要理解了题目要求,认真分析,便能很好地完成这两次作业。而对于这些地方还应进行深入研究与思考。希望老师可以在课堂上多讲解有关类设计的实例和作业的讲解。
浙公网安备 33010602011771号