1.前言:
本次是第三次对面向对象程序设计题目集的总结分析博客。第一次的Java的作业比较简单,后面两次有些题目开始有点复杂,主要开始涉及到多个类。
2.设计与分析:
1.第一次作业:第一次作业主要用到输入输出已经String类型的运用,和if-else或者switch判断的用法。
输入三角形三条边,判断该三角形为什么类型的三角形。
输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[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) { Scanner input=new Scanner(System.in); float sideA,sideB,sideC; sideA=input.nextFloat(); sideB=input.nextFloat(); sideC=input.nextFloat(); if(sideA<1||sideA>200||sideB<1||sideB>200||sideC<1||sideC>200) { System.out.print("Wrong Format"); } else { if((sideA+sideB>sideC)&&(sideA+sideC>sideB)&&(sideB+sideC>sideA)) { if(sideA==sideB||sideA==sideC||sideB==sideC) { if((sideA==sideB)&&(sideB==sideC)) System.out.print("Equilateral triangle"); else if(((Math.abs(sideA*sideA+sideB*sideB-sideC*sideC)<0.00001)||Math.abs(sideA*sideA+sideC*sideC -sideB*sideB)<0.00001)||Math.abs(sideB*sideB+sideC*sideC-sideA*sideA)<0.00001) System.out.print("Isosceles right-angled triangle"); else System.out.print("Isosceles triangle"); } else { if((sideA*sideA+sideB*sideB==sideC*sideC)||(sideA*sideA+sideC*sideC ==sideB*sideB)||(sideB*sideB+sideC*sideC==sideA*sideA)) System.out.print("Right-angled triangle"); else System.out.print("General triangle"); } } else System.out.print("Not a triangle"); } } }
这里我主要用if-else语句去判断,判断的也比较简单粗暴,所以判断很多,应该还可以在优化下
2.第二次作业:第二次作业的难度比第一次要大一点,逐渐开始对类的运用比较多,特别是菜单的那道题,对于习惯用c语言面向过程编程,对于面向对象还是有些不熟悉
某饭店提供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)
//添加一条菜品信息到订单中。
}
类图:
类的代码:
//菜品类:对应菜谱上一道菜的信息。 class Dish { String name;//菜品名称 int unit_price; //单价 int getPrice(int portion){//计算菜品价格的方法,输入参数是点菜的份额(输入数据只能是1/2/3,代表小/中/大份) if(portion==1) return unit_price; else if(portion==2) return (int)(unit_price*1.5); else return unit_price*2; } } //菜谱类:对应菜谱,包含饭店提供的所有菜的信息。 class Menu { Dish[] dishs;//菜品数组,保存所有菜品信息 Menu(){ dishs=new Dish[4]; for(int i=0;i<4;i++) dishs[i]=new Dish(); dishs[0].name="西红柿炒蛋"; dishs[0].unit_price=15; dishs[1].name="清炒土豆丝"; dishs[1].unit_price=12; dishs[2].name="麻婆豆腐"; dishs[2].unit_price=12; dishs[3].name="油淋生菜"; dishs[3].unit_price=9; } Dish searthDish(String dishName){//根据菜名在菜谱中查找菜品信息,返回Dish对象。 for(Dish dish:dishs) { if(dish.name.equals(dishName)) return dish; } return null; } } //点菜记录类:保存订单上的一道菜品记录 class Record { Dish d;//菜品 int portion;//份额(1/2/3代表小/中/大份) int getPrice(){//计价,计算本条记录的价格 return d.getPrice(portion); } } //订单类:保存用户点的所有菜的信息。 class Order { Record[] records;//保存订单上每一道的记录 Order() { records=new Record[10]; } int getTotalPrice(){//计算订单的总价 int sum=0; for(Record record:records) { // 在for循环中,可以利用“变量类型 变量名称 : 数组名称”的形式,直接把数组元素赋值给该变量 if (record != null) { // 添加判空条件,避免空指针异常 sum+=record.getPrice(); } } return sum; } Record addARecord(String dishName,int portion) {//添加一条菜品信息到订单中。 Record record=new Record(); record.d.name=dishName; record.portion=portion; return record; } }
- 给定一个日期,判定是否为合法日期。如果合法,判断该年是否闰年,该日期是当年第几天、当月第几天、当周第几天、。
- 给定起始日期与结束日期,判定日期是否合法且结束日期是否早于起始日期。如果均合法,输出结束日期与起始日期之间的相差的天数、月数、念书。
输入格式:
第一行输入一个日期字符串,格式为"YYYY-MM-dd"
第二行输入两个日期字符串,中间使用空格隔开。分别代表开始日期与结束日期。
输出格式:
如果第一行日期字符串非法,输出自定义的错误信息。
如果第一行日期有效,输出相关信息,如果是闰年要输出是闰年。
如果第二行两个日期,只要有一个无效。就输出相关错误信息。
如果第二行两个日期有效且结束日期不早于开始日期,输出相关信息。
分析:
对于java时间的处理,可以用java的时间类,比如这道题就算,用的类如下
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Scanner;
代码:
import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoUnit; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner input=new Scanner(System.in); String dateStr = input.nextLine(); String rangeStr = input.nextLine(); //2021-02-28 if(!dateStr.matches("[0-9]{4}-[0-9]{2}-[0-9]{2}")) System.out.println(dateStr + "无效!"); else { int year=Integer.parseInt(dateStr.substring(0, 4)); int month=Integer.parseInt(dateStr.substring(5, 7)); int day=Integer.parseInt(dateStr.substring(8)); if (!isValid(year,month,day)) System.out.println(dateStr + "无效!"); else { // 解析日期字符串为LocalDate对象,并获取年、月、日 LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); if(isLeapYear(year)) System.out.println(dateStr+"是闰年."); System.out.println(dateStr+"是当年第"+ date.getDayOfYear()+"天,当月第"+day+"天,当周第" +date.getDayOfWeek().getValue()+"天."); } } String[] dates=rangeStr.split(" "); if(!dates[0].matches("[0-9]{4}-[0-9]{2}-[0-9]{2}")||!dates[1].matches("[0-9]{4}-[0-9]{2}-[0-9]{2}")) System.out.println(dates[0] + "或" + dates[1] + "中有不合法的日期."); else { int year_1 = Integer.parseInt(dates[0].substring(0, 4)); int month_1 = Integer.parseInt(dates[0].substring(5, 7)); int day_1 = Integer.parseInt(dates[0].substring(8)); int year_2 = Integer.parseInt(dates[1].substring(0, 4)); int month_2 = Integer.parseInt(dates[1].substring(5, 7)); int day_2 = Integer.parseInt(dates[1].substring(8)); if(!isValid(year_1,month_1,day_1)||!isValid(year_2,month_2,day_2)) System.out.println(dates[0] + "或" + dates[1] + "中有不合法的日期."); else { LocalDate startDate = LocalDate.parse(dates[0], DateTimeFormatter.ofPattern("yyyy-MM-dd")); LocalDate endDate = LocalDate.parse(dates[1], DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 判断结束日期是否早于开始日期 if (endDate.isBefore(startDate)) { System.out.println(dates[1]+"早于"+dates[0]+",不合法!"); return; } long daysDiff = ChronoUnit.DAYS.between(startDate, endDate); // 输出日期差 System.out.println(dates[1]+"与"+dates[0]+"之间相差"+daysDiff+"天,所在月份相差"+ (month_2-month_1)+",所在年份相差"+(year_2-year_1)+"."); } } } public static boolean isValid(int year, int month, int day) { // 检查月份是否在有效范围内 if (month < 1 || month > 12) { return false; } // 检查日期是否在有效范围内 if (day < 1 || day > 31) { return false; } // 对不同的月份进行特殊处理 if (month == 2) { // 2月 // 检查是否为闰年 boolean isLeapYear = isLeapYear(year); if (isLeapYear && day > 29) { return false; } else if (!isLeapYear && day > 28) { return false; } } else if (month == 4 || month == 6 || month == 9 || month == 11) { // 小月 if (day > 30) { return false; } } return true; } // 判断年份是否为闰年 public static boolean isLeapYear(int year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } }
第三次作业:
某高校课程从性质上分为:必修课、选修课,从考核方式上分为:考试、考察。
考试的总成绩由平时成绩、期末成绩分别乘以权重值得出,比如平时成绩权重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)成绩平均分只取整数部分,小数部分丢弃
参考类图:
这道题情况比较多,有点复杂,我没写出来,这里只能给一些我的思路和设计的类
我用到的类主要有以下这些
class Course{//课程 String courseName; String courseNature;//课程性质,必修或选修 String courseAssess;//考核方式 public Course(String courseName,String courseNature,String courseAssess) { this.courseName=courseName; this.courseNature=courseNature; this.courseAssess=courseAssess; } public boolean isCourse() { if(courseNature.equals("必修")&&!courseAssess.equals("考试")) { System.out.println(courseName+" : course type & access mode mismatch"); return false; } else return true; } } class Grade{ //课程成绩 String num; String StudentName; String courseName; int usualGrades; int finalGrades; Grade(){ } public Grade(String num,String StudentName,String courseName,int usualGrades, int finalGrades) { this.num=num; this.StudentName=StudentName; this.courseName=courseName; this.usualGrades=usualGrades; this.finalGrades=finalGrades; } public int getUsualGrade() { return usualGrades; } public int getFinalGrades() { return finalGrades; } public int getTotalGrade() { return (int)(usualGrades*0.3+finalGrades*0.7); } } class ExamGrade extends Grade {//考核成绩 int examGrade; public ExamGrade(){ examGrade=(int)(usualGrades*0.3+finalGrades*0.7); } } class ExamineGrades extends Grade{//考察成绩 int examineGrades; ExamineGrades(){ examineGrades=finalGrades; } }
三.心得体会
踩坑心得:一开始写日期的题目,没有了解到java中一些自带的时间类,可以直接用自带的时间类,在计算时间上会方便很多。还有比如判断输入之类。还是日期那道题,就因为判断输入格式不正确,所以有两个测试点没有过,后来用了正则表达式来判断就方便的多。
总结:通过这几次的作业,我开始会用面向对象的思想去解决问题,当然还有些不熟练,这些要通过练习来进步