java1-3作业总结
目录:
- 前言
- 设计与分析
- 踩坑心得
- 主要困难以及改进建议
- 总结
一、前言
1.第一次作业比较简单,题目量虽大,但解题思路简单,涉及的类少,考察点为Java语法的基本运用,比如一些数据的声明,浮点数的应用,循环语句,需要注意的是Java输入输出语句的格式。对于刚接触Java的我们,这次作业为完成后续的Java作业打下了基础。
2.第二次作业难度上升,题目量少,但部分题目仍需要花心思思考,涉及的类也增加了,这次题目集主要考察对类的定义与使用,以及对对象的封装和使用,加深了我对Java的进一步了解,也为后续的题目集提供了参考思路。
3.第三次作业重点在第一二题,其他题目并没有什么难度,第二题无论是类的设计与使用,类的封装,类与类之间的调用关系,对于我来说,难度无疑是增加了。
二、设计与分析
1.第一次作业 7-7判断三角形类型
输入三角形三条边,判断该三角形为什么类型的三角形。
输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[1,200]。
输出格式:
(1)如果输入数据非法,则输出“Wrong Format”;
(2)如果输入数据合法,但三条边不能构成三角形,则输出“Not a triangle”;
(3)如果输入数据合法且能够成等边三角形,则输出“Equilateral triangle”;
(3)如果输入数据合法且能够成等腰直角三角形,则输出“Isosceles right-angled triangle”;
(5)如果输入数据合法且能够成等腰三角形,则输出“Isosceles triangle”;
(6)如果输入数据合法且能够成直角三角形,则输出“Right-angled triangle”;
(7)如果输入数据合法且能够成一般三角形,则输出“General triangle”。
import java.util.Scanner; public class Main{ public static void main(String[] args){ boolean Isosceles=false,Angled = false; Scanner input = new Scanner(System.in); double i = input.nextDouble(); double j = input.nextDouble(); double k = input.nextDouble(); if(i<1||i>200||j<1||j>200||k<1||k>200) { System.out.println("Wrong Format"); return; } if(i+j<=k||i+k<=j||j+k<=i) { System.out.println("Not a triangle"); return; } if(i==j||j==k||i==k) { Isosceles = true; } if(Math.abs(i*i+j*j-k*k)<0.000001||Math.abs(j*j+k*k-i*i)<0.000001||Math.abs(i*i+k*k-j*j)<0.000001) { Angled = true; } if(i==j&&j==k&&i==k) { System.out.println("Equilateral triangle"); return; } if(Isosceles&&Angled) { System.out.println("Isosceles right-angled triangle"); return; } else if(Isosceles) { System.out.println("Isosceles triangle"); return; } else if(Angled) { System.out.println("Right-angled triangle"); return; } else{ System.out.println("General triangle"); return; } } }
此题需要注意的是用浮点数比较使用了Math.abs()方法进行误差范围判断,以及反向判断三角形。
2.第二次作业7-1 成绩计算-1-类、数组的基本运用
创建学生类,包含
属性:学号(String)、姓名(String)、语文成绩(int)、数学成绩(int)、物理成绩(int)
方法:计算总分、计算平均分
输入5个学生的信息,将每个学生的信息封装在一个学生对象中。
按输入顺序依次输出5个学生的总分、平均分(精确到小数点后两位,舍去部分按四舍五入规则计入最后一位)。
import java.util.Scanner; public class Main{ public static class Student{ private String number; private String name; private int chinesegrade; private int mathgrade; private int achievement; public Student(String number,String name,int chinesegrade,int mathgrade,int achievement) { this.number = number; this.name = name; this.chinesegrade =chinesegrade; this.mathgrade =mathgrade; this.achievement =achievement; } public String getStudentNumber(){ return number; } public String getStudentName(){ return name; } public int getStudentChinesegrade(){ return chinesegrade; } public int getStudentMathgrade(){ return mathgrade; } public int getStudentAchievement(){ return achievement; } public int getSum() { return chinesegrade+mathgrade+achievement; } public double getAvg() { return getSum()/3.0; } } public static void main(String[] args){ Scanner input = new Scanner(System.in); Student[]student = new Student[5]; for (int i=0;i<5;i++) { String number=input.next(); String name=input.next(); int chinesegrade=input.nextInt(); int mathgrade=input.nextInt(); int achievement=input.nextInt(); student[i] = new Student(number,name,chinesegrade,mathgrade,achievement); } for(int i=0;i<5;i++) { System.out.printf("%s %s %d %.2f\n",student[i].getStudentNumber(),student[i].getStudentName(),student[i].getSum(),student[i].getAvg()); } } }
此题比较简单,只需要一个·Student类,封装学生类也很简单,通过此题我掌握了封装对象的方法。定义对象数组用来存放五个学生对象。这题需要注意的是输出的成绩需保留两位小数。在网上学习了方法,最后输出无误。
类图:
圈复杂度:
2.第二次作业7-2 成绩计算-2-关联类
创建成绩类,包含:
属性:平时成绩(int)、期末成绩(int)
方法:计算总成绩(计算规则:平时成绩*0.4+期末成绩*0.6,保留整数部分,小数部分直接丢弃)
创建学生类,包含:
属性:学号(String)、姓名(String)、语文成绩(成绩类)、数学成绩(成绩类)、物理成绩(成绩类)
方法:计算总分、计算平均分
输入3个学生的信息,将每个学生的信息封装在一个学生对象中。
按输入顺序依次输出3个学生的总分、平均分(精确到小数点后两位,舍去部分按四舍五入规则计入最后一位)。
浮点数保留小数的相关知识可参考:https://blog.csdn.net/huaishuming/article/details/17752365
注意:未用学生类对象封装数据的,本题计0分
import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner input = new Scanner(System.in); Student[] student = new Student[3]; Score[][] s = new Score[3][3]; for(int i = 0;i < 3 ;i++) { student[i]=new Student(); } for(int i = 0;i < 3 ;i++) { for(int j = 0;j<3;j++) { s[i][j]=new Score(); } } double m=0,n=0,k=0; int []scores1 = new int[3]; int []scores2 = new int[3]; int []scores3 = new int[3]; for(int i = 0;i<3 ;i++) { for(int j = 0;j<3;j++) { student[i].number=input.next(); student[i].name=input.next(); String lesson = input.next(); s[i][j].usualperformance=input.nextInt(); s[i][j].finalscore=input.nextInt(); m+=s[i][j].sum(); n+=s[i][j].usualperformance; k+=s[i][j].finalscore; } scores1[i] = (int)m; scores2[i] = (int)n; scores3[i] = (int)k; m=0; n=0; k=0; } for(int i = 0;i<3 ;i++) { System.out.printf("%s %s %d %.2f %.2f %.2f\n",student[i].getStudentNumber(),student[i].getStudentName(),scores1[i],scores2[i]/3.0,scores3[i]/3.0,scores1[i]/3.0); } } public static class Student{ private String number; private String name; private int chinesegrade; private int mathgrade; private int achievement; public Student(String number,String name,int chinesegrade,int mathgrade,int achievement) { this.number = number; this.name = name; this.chinesegrade =chinesegrade; this.mathgrade =mathgrade; this.achievement =achievement; } public Student() { } public String getStudentNumber(){ return number; } public String getStudentName(){ return name; } public int getStudentChinesegrade(){ return chinesegrade; } public int getStudentMathgrade(){ return mathgrade; } public int getStudentAchievement(){ return achievement; } public int getSum() { return chinesegrade+mathgrade+achievement; } public double getAvg() { return getSum()/3.0; } } public static class Score { private int usualperformance; private int finalscore; public int sum() { return (int)(0.4*usualperformance+0.6*finalscore); } public Score(int usualperformance,int finalscore) { this.usualperformance = usualperformance; this.finalscore = finalscore; } public Score() { this(0,0); } } }
此题是第一题的升级版,我用了两个类,Student类和Score类,Student类用于记录学生的学号、姓名、语文成绩、数学成绩、物理成绩。其中还有求三门课的总成绩以及平均成绩的方法。成绩类用于记录学生的平时成绩和期末成绩。创建一个对象数组存放三个学生的信息,创建二维数组存放三个学生的三门科目的平时成绩,期末成绩和总成绩。创建三个一维数组分别存放所有科目总成绩之和,平时成绩之和,期末成绩之和。for循环输入输出学生信息。运用this(0,0),可以实现代码复用和默认数值初始化的效果,提高了代码的简洁性和可读性。通过在有参构造函数中定义初始化操作,然后在无参构造函数中调用有参构造函数,可以避免两个构造函数中相同的初始化代码重复编写,提高了代码的可维护性。无参构造函数在对象创建时会被调用,通过使用 this(0,0)
,将默认的初值0传递给有参构造函数,确保对象在创建时拥有合理的初始数值。
类图:
圈复杂度:
3.第二次作业7-3有重复数据
在一大堆数据中找出重复的是一件经常要做的事情。现在,我们要处理许多整数,在这些整数中,可能存在重复的数据。
你要写一个程序来做这件事情,读入数据,检查是否有重复的数据。如果有,输出“YES
”这三个字母;如果没有,则输出“NO
”。
import java.util.Scanner; import java.util.LinkedHashSet; import java.util.Set; public class Main { public static void main(String[] args) { Scanner input= new Scanner(System.in); int n=input.nextInt(); LinkedHashSet<Integer> m=new LinkedHashSet<Integer>(); int i = 0; for (i = 0;i < n;i++) { m.add(input.nextInt()); } input.close(); int j = m.size(); if(j!=n) { System.out.print("YES"); } else { System.out.print("NO"); } } }
代码的逻辑为创建一个Scanner对象input,用于从控制台读取输入。从输入中读取一个整数n,表示接下来要输入的数字个数。创建一个LinkedHashSet集合m,用于存储输入的数字,并保持输入顺序。使用一个循环,从控制台读取n个数字,并将它们添加到集合m
中。由于LinkedHashSet会自动去重,所以如果有重复的数字,它们只会被添加一次。关闭Scanner对象input,释放资源。获取集合m的大小,即不重复数字的个数。如果集合大小与输入的数字个数n不相等,说明存在重复数字,输出"YES";否则,输出"NO"。
类图:
4.第二次作业7-4菜单计价程序
某饭店提供4种菜,每种菜品的基础价格如下:
西红柿炒蛋 15
清炒土豆丝 12
麻婆豆腐 12
油淋生菜 9
设计点菜计价程序,根据输入的订单,计算并输出总价格。
订单由一条或多条点菜记录组成,每条记录一行,最后以"end"结束
每条点菜记录包含:菜名、份额两个信息。
份额可选项包括:1、2、3,分别代表小、中、大份)
不同份额菜价的计算方法:
小份菜的价格=菜品的基础价格。
中份菜的价格=菜品的基础价格1.5。
小份菜的价格=菜品的基础价格2。
如果计算出现小数,按四舍五入的规则进行处理。
参考以下类的模板进行设计:
菜品类:对应菜谱上一道菜的信息。
Dish {
String name;//菜品名称
int unit_price; //单价
int getPrice(int portion)//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份)
}
菜谱类:对应菜谱,包含饭店提供的所有菜的信息。
Menu {
Dish[] dishs ;//菜品数组,保存所有菜品信息
Dish searthDish(String dishName)//根据菜名在菜谱中查找菜品信息,返回Dish对象。
}
点菜记录类:保存订单上的一道菜品记录
Record {
Dish d;//菜品
int portion;//份额(1/2/3代表小/中/大份)
int getPrice()//计价,计算本条记录的价格
}
订单类:保存用户点的所有菜的信息。
Order {
Record[] records;//保存订单上每一道的记录
int getTotalPrice()//计算订单的总价
Record addARecord(String dishName,int portion)
//添加一条菜品信息到订单中。
}
import java.util.Scanner; public class Main { public static void main(String [] args) { Scanner input = new Scanner(System.in); String dish; String[]menu = new String[4]; menu[0] = "西红柿炒蛋"; menu[1] = "清炒土豆丝"; menu[2] = "麻婆豆腐"; menu[3] = "油淋生菜"; int price=0; int size; int count=0; for(;;) { dish=input.next(); if(dish.equals("end"))break; size = input.nextInt(); if(dish.equals(menu[0])) { count=1; if(size==1) price= price+15; if(size==2) price= price+23; if(size==3) price= price+30; } else if(dish.equals(menu[1])) { count=1; if(size==1) price= price+12; if(size==2) price= price+18; if(size==3) price= price+24; } else if(dish.equals(menu[2])) { count=1; if(size==1) price= price+12; if(size==2) price= price+18; if(size==3) price= price+24; } else if(dish.equals(menu[3])) { count=1; if(size==1) price= price+9; if(size==2) price= price+14; if(size==3) price= price+18; } else { System.out.println(dish+" does not exist"); } } System.out.println(price); } }
这个题目我并没有根据题目来设置类处理各个对象之间的关系,而是通过使用了条件语句和循环来处理不同的情况。
类图:
圈复杂度:
5.第三次作业7-4菜单计价程序
某高校课程从性质上分为:必修课、选修课,从考核方式上分为:考试、考察。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重0.3,期末成绩权重0.7,总成绩=平时成绩*0.3+期末成绩*0.7。
考察的总成绩直接等于期末成绩
必修课的考核方式必须为考试,选修课可以选择考试、考察任一考核方式。
1、输入:
包括课程、课程成绩两类信息。
课程信息包括:课程名称、课程性质、考核方式(可选,如果性质是必修课,考核方式可以没有)三个数据项。
课程信息格式:课程名称+英文空格+课程性质+英文空格+考核方式
课程性质输入项:必修、选修
考核方式输入选项:考试、考察
课程成绩信息包括:学号、姓名、课程名称、平时成绩(可选)、期末成绩
课程信息格式:学号+英文空格+姓名+英文空格+课程名称+英文空格+平时成绩+英文空格+期末成绩
以上信息的相关约束:
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.util.*; public class Main { static class Student { private String studentId; private String name; private Map<String, CourseGrade> courseGrades; public Student(String studentId, String name) { this.studentId = studentId; this.name = name; this.courseGrades = new HashMap<>(); } public void addCourseGrade(CourseGrade courseGrade) { courseGrades.put(courseGrade.getCourseName(), courseGrade); } public String getStudentId() { return studentId; } public String getName() { return name; } public Map<String, CourseGrade> getCourseGrades() { return courseGrades; } } static class CourseGrade { private String courseName; private String courseType; private String examType; private List<Integer> grades; public CourseGrade(String courseName, String courseType, String examType) { this.courseName = courseName; this.courseType = courseType; this.examType = examType; this.grades = new ArrayList<>(); } public void addGrade(int grade) { grades.add(grade); } public String getCourseName() { return courseName; } public String getCourseType() { return courseType; } public String getExamType() { return examType; } public List<Integer> getGrades() { return grades; } public boolean hasGrades() { return !grades.isEmpty(); } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); Map<String, CourseGrade> courseGradeMap = new LinkedHashMap<>(); Map<String, Student> studentMap = new HashMap<>(); Map<String, Integer> classTotalGrades = new HashMap<>(); while (scanner.hasNextLine()) { String input = scanner.nextLine(); if (input.equals("end")) { break; } String[] parts = input.split(" "); int len = parts.length; if (len != 3 ) { System.out.println("wrong format"); continue; } String courseName = parts[0]; String courseType = parts[1]; String examType = parts[2]; // Check if course already exists CourseGrade courseGrade = courseGradeMap.get(courseName); if (courseGrade == null) { courseGrade = new CourseGrade(courseName, courseType, examType); courseGradeMap.put(courseName, courseGrade); } else { // Check if course type and exam type match if (!courseType.equals(courseGrade.getCourseType()) || !examType.equals(courseGrade.getExamType())) { System.out.println(courseName + " : course type & access mode mismatch"); continue; } } } // Sort courses by course name List<CourseGrade> sortedCourses = new ArrayList<>(courseGradeMap.values()); // Output course average grades for (CourseGrade courseGrade : sortedCourses) { String courseName = courseGrade.getCourseName(); if (!courseGrade.hasGrades()) { System.out.println(courseName + " has no grades yet"); continue; } List<Integer> grades = courseGrade.getGrades(); int regularGradeSum = 0; int finalGradeSum = 0; for (int grade : grades) { if (grade <= 100) { finalGradeSum += grade; } else { regularGradeSum += grade - 100; } } int regularGradeCount = grades.size() - finalGradeSum; int finalGradeCount = grades.size() - regularGradeSum; double regularGradeAverage = Math.round((double) regularGradeSum / regularGradeCount); double finalGradeAverage = Math.round((double) finalGradeSum / finalGradeCount); double totalGradeAverage = Math.round((double) (regularGradeSum + finalGradeSum) / grades.size()); System.out.println(courseName + " " + regularGradeAverage + " " + finalGradeAverage + " " + totalGradeAverage); } scanner.close(); } public static boolean isNumeric(String str) { try { Integer.parseInt(str); return true; } catch (NumberFormatException e) { return false; } } }
定义了两个内部类Student
和 CourseGrade
。其中,Student
表示学生,包含学生ID、姓名和课程成绩的映射关系,CourseGrade
表示课程成绩,包含课程名称、课程类型、考试类型以及成绩列表。
三、踩坑心得
1. 第一次作业总体比较简单,但面对这题判断直角三角形上,并没有想到用两边之和与第三边的差的绝对值小于很小的数来判断,一开始我只是非常直观的用两条边的平方和等于第三条边的平方来判断,后在网上查询资料知道了浮点数比较使用了Math.abs()方法进行误差范围判断,即两个浮点数的差的绝对值小于0.000001被认为是相等的方法。一开始判断三角形的类型以及输入的数据是否合法我都是直接判断的,并没有才有反向判断,导致部分测试点没过。一开始也没有想着用boolean类型判断等腰直角三角形,代码报错提醒我判断语句的问题,我才想着用此类型。通过这题我也学到了很多,在ifelse语句判断的先后问题上也出过差错,知道了语句的先后问题也会影响其运行结果。
我的错误示例:
正面判断三角形导致部分答案正确
if-else语句的逻辑不同导致部分答案正确
2.第二次作业7-2 成绩计算-2-关联类需要注意的是成绩输出要保留两位小数,需要注意的是循环中m存储当前学生的总分之和,n存储了当前学生的平时成绩之和,k存储了当前学生的期末成绩之和,需要将其初始值为0,否则mnk存储了多个学生的成绩之和。
我的错误示例:
mnk忘记重新置零导致答案错误
3.第二次作业7-3有重复数据,刚开始我采用的是数组存放输入的数据,但是会运行超时。后来在网上查找资料了解到LinkedHashSet会自动去重,边采用LinkedHashSet存放输入的数据,但仍存在问题。
我的错误示例:
采用数组存放数据:
采用LinkedHashSet存放输入数据
4.第二次作业7-4菜单计价程序,这道题目我没有按照题目提示设置多个类来处理情况,就用了数组来存储菜单,多个变量反映数据状态,条件语句和循环来处理不同的情况,逻辑清晰,不容易出错,但初始化数组的不同导致部分测试点没过,我感到十分意外。
我的错误示例:
四、 主要困难以及改进建议
主要困难:第三次作业第二题异常处理不完善,代码中没有对可能出现的异常进行处理,比如输入数据类型错误导致的异常或除数为零导致的异常等。在实际应用中,应该添加适当的异常处理机制,以提高代码的健壮性和稳定性。
改进建议:目前代码中使用了基本的面向对象思想,但可以进一步优化,可将学生、课程和成绩等相关操作封装成类的方法,并提供合理的访问控制,以提高代码的可复用性和可维护性。
五、总结
这是本学期Java第一阶段的学习,能看到自己获得了知识,但更多的是自己的不足,而且不足之处很明显。学习的东西虽然基础,但是掌握却需要大量联系。从最初适应c语言变成Java语言,然后认识Java基础语言,再到后面运用多个类编写程序。作为初学者,发现还有许多东西需要去掌握:
1.基础语法的巩固,在进行Java编程中,时常脱离不出C语言的习惯,导致出现语法错误,甚至不记得如何进行编写,这需要在练习中,不要只会对之前自己写的代码复制粘贴,还要留意写法。
2.多学习使用eclipse,这个编译软件很好用,功能很多,自动报错的功能对于代码的修改很有帮助,写pta不能只在那上面写代码,灵活运用eclipse对自己编写修改代码很有帮助。
3.不同类之间的关系,许多时候正是不知如何进行将类互相呼应,导致代码亢长,产生垃圾代码,这不利于学习;当能够了解,并运用类与类之间的关系,则能解决大多数问题。
最后,我觉得我需要多实践、多交流。只有真正动手实践,才能发现问题、解决问题、积累经验。同时,与其他同学多进行交流和分享,可以获得更多的经验和技巧。