OOP前三次作业总结
前言:
我在面向对象程序设计课程开课之前,没有接触过Java,在老师的引导下开始认识这一门语言。
前三次题目集主要是针对语法和类的基本知识进行考察。第一次的题目集题量较多,但全是针对Java基础的语法,难度小。第二次的题目集开始涉及构造方法,调用方法,题量适中,难度较小。第三次的题目集开始涉及不同的类,属性,带参数构造方法、无参构造方法、属性的getter、setter方法等,题量较少,但难度明显大于前两次的题目集。
具体分析三次题目集和部分题目:
(包括设计分析、踩坑心得和改进建议)
第一次题目集:
一共12道题,但知识涉及基本的语法,例如输入、输出、if判断、循环等,难度低,做起来比较轻松。印象比较深刻的是

我觉得用英语表述的题目在题意的理解上更有趣些。对一定范围内素数的求和,题目在学习C语言的时候接触过,所以做起来比较轻松,只是转换一下,使用Java的语言写一遍。
第二次题目集:
一共9道题,考察的知识主要还是语法,稍涉及一些方法。经过第一次题目集的练习,对基本的语法有一个大概的了解,所以做起来比第一次还要快些。以7-8为例。

实现的代码:
1 import java.util.Scanner; 2 3 public class Main{ 4 public static void main(String[] args){ 5 Scanner in = new Scanner(System.in); 6 int i = 0,j = 0; 7 float k; 8 //三角形三条边的输入 9 float a = in.nextFloat(); 10 float b = in.nextFloat(); 11 float c = in.nextFloat(); 12 //按照长度交换三边a,b,c的值,方便下面的判断 13 for(i = 0;i < 3;i++){ 14 if(a>b){ 15 k = b; 16 b = a; 17 a = k; 18 } 19 if(b > c){ 20 k = c; 21 c = b; 22 b = k; 23 } 24 } 25 if(a < 1 || c > 200){ 26 System.out.println("Wrong Format"); 27 }else if( a + b <= c){ 28 System.out.println("Not a triangle"); 29 }else if(a == b && b == c){ 30 System.out.println("Equilateral triangle"); 31 }else if(a == b && a*a + b*b - c*c < 0.000001){ 32 System.out.println("Isosceles right-angled triangle"); 33 }else if(a == b||b == c){ 34 System.out.println("Isosceles triangle"); 35 }else if(a*a + b*b == c*c){ 36 System.out.println("Right-angled triangle"); 37 }else{ 38 System.out.println("General triangle"); 39 } 40 } 41 }
在实现的过程中,整体思路是利用三角形的三边关系——两边之和大于第三边来判断三角形是否能形成,再按照各种三角形的条件结合if语句来判断其类型。题目比较简单,但在判断等腰直角三角形的测试点中遇到一个问题,多次测试不同数据都过不了。后面通过搜索发现计算机无法准确处理无理数数据,因此等腰直角三角形的边长比关系无法直接体现,而要通过一定的误差判断来解决。等腰直角三角形的判断条件也就改成了a == b && a*a + b*b - c*c < 0.000001。这样测试点就过了。
第三次题目集:
一共四道题,内容涉及设计一个类,属性,带参数构造方法、无参构造方法、属性的getter、setter等具体方法。虽然题目量少,但难度明显前两次大。因为对类和方法了解的并不多,所以做起来比较吃力,花费的时间较长。以7-3和7-4两题为例。

这道题已经给出了类图,所以只需要根据类图设计完善方法就行了。
实现的部分代码如下:
import java.util.Scanner; class Date{ private int year; private int month; private int day; private int monmaxnum[] = new int [] {0,31,28,31,30,31,30,31,31,30,31,30,31}; //缺少了带参数的构造方法,导致后面还需要调用setter方法传入变量的值 public Date() { } public int getDay() { return day; } public void setDay(int day) { this.day = day; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public void isLeapYear() { if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { monmaxnum [2] = 29; } } public boolean checkInputValidity() { if(year <= 2000 && year >= 1900 && month > 0 && month <= 12 && day <= monmaxnum[month] && day > 0) { return true; }else { return false; } } public void getNextDay() { if(day == monmaxnum[month]) { month = month + 1; day = 1; }else { day = day + 1; } if(month > 12) { year = year + 1; month = 1; } } } public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int year1 = in.nextInt(); int month1 = in.nextInt(); int day1 = in.nextInt(); Date date = new Date(); date.setYear(year1); date.setMonth(month1); date.setDay(day1); date.isLeapYear(); if(date.checkInputValidity()) { date.getNextDay(); System.out.println("Next day is:"+date.getYear()+"-"+date.getMonth()+"-"+date.getDay()); }else { System.out.println("Date Format is Wrong"); } } }
因为是第一次写一个类,尽管老师在课上讲述了方法,在使用的时候还是感觉力不从心,有很多地方都不清楚。比如类图中要求设计带参数构造方法和无参构造方法,而因为对类图和类设计的不了解,认为只需要设计属性。因此在后面改变Date类中的变量的值时变得非常麻烦,多次使用属性的setter方法。后面发现其实只要设计带参数构造方法,在构造一个带参数的对象的时候就可以一次性将值全部传入。
具体改进:
增加带参的构造方法:
public Date(int year,int month,int day) {
this.month = month;
this.day = day;
this.year = year;
int monmaxnum[] = new int [] {0,31,28,31,30,31,30,31,31,30,31,30,31};
}
将源码中的
Date date = new Date();
date.setYear(year1);
date.setMonth(month1);
date.setDay(day1);
改为
Date date = new Date(year1,month1,day1);
7-4这题并没有类图(多亏没有,不然一下看不懂又要吃大亏),但是给了类需要编写的具体方法(还带说明,对初学者来说这比类图清楚太多了)。只需要编写类的方法,程序的主方法已经给了。7-4题目难度较前面的题目而言难度比较大,花费的时间较长,印象深刻。
import java.util.Scanner; class DateUtil{ private int year; private int month; private int day; private int monmaxnum[] = new int [] {0,31,28,31,30,31,30,31,31,30,31,30,31}; public DateUtil() { } public DateUtil(int year,int month,int day) { this.month = month; this.day = day; this.year = year; int monmaxnum[] = new int [] {0,31,28,31,30,31,30,31,31,30,31,30,31}; } public boolean checkInputValidity(){ if(year >= 1820 && year <= 2020 && month > 0 && month <= 12 && day <= monmaxnum[month]) { return true; }else { return false; } }//检测输入的年、月、日是否合法 public boolean isLeapYear(int year) { if(year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { return true; } else { return false; } }//判断year是否为闰年 public DateUtil getNextNDays(int n) { if(isLeapYear(year)) { monmaxnum[2] = 29; } else { monmaxnum[2] = 28; } if(n > monmaxnum[month]) { n = n - monmaxnum[month]; month++; } day = day + n; while(day > monmaxnum[month]) { day = day - monmaxnum[month]; month++; if(month>12) { month = 1; year++; if(isLeapYear(year)) { monmaxnum[2] = 29; } else { monmaxnum[2] = 28; } } } DateUtil date1 = new DateUtil(year,month,day); return date1; }//取得year-month-day的下n天日期 public DateUtil getPreviousNDays(int n) { day = day - n; if(isLeapYear(year)) { monmaxnum[2] = 29; } else { monmaxnum[2] = 28; } while(day <= 0) { month--; if(month == 0) { month = 12; year--; if(isLeapYear(year)) { monmaxnum[2] = 29; } else { monmaxnum[2] = 28; } } day = day + monmaxnum[month]; } DateUtil date2 = new DateUtil(year,month,day); return date2; }//取得year-month-day的前n天日期 public boolean compareDates(DateUtil date) { if(year < date.year) { return true; }else if(year == date.year && month < date.month ) { return true; }else if(year == date.year && month == date.month && day < date.day) { return true; }else { return false; } }//比较当前日期与date的大小(先后) public boolean equalTwoDates(DateUtil date) { if(year == date.year && month == date.month && day == date.day) { return true; }else { return false; } }//判断两个日期是否相等 public int getDaysofDates(DateUtil date) { int daynum = 0; while(compareDates(date) && date.year * 12 + date.month > year * 12 + month) { if(isLeapYear(year)) { monmaxnum[2] = 29; } else { monmaxnum[2] = 28; } daynum += monmaxnum[month]; month++; if(month>12) { month = 1; year ++; } } if(!equalTwoDates(date)) { daynum = daynum + date.day - day; } return daynum; }//求当前日期与date之间相差的天数 public String showDate() { return year+"-"+month+"-"+day; }//以“year-month-day”格式返回日期值 public int getDay() { return day; } public void setDay(int day) { this.day = day; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } } public class Main { public static void main(String[] args) { Scanner input = new Scanner(System.in); int year = 0; int month = 0; int day = 0; int choice = input.nextInt(); if (choice == 1) { // test getNextNDays method int m = 0; year = Integer.parseInt(input.next()); month = Integer.parseInt(input.next()); day = Integer.parseInt(input.next()); DateUtil date = new DateUtil(year, month, day); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } m = input.nextInt(); if (m < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:"); System.out.println(date.getNextNDays(m).showDate()); } else if (choice == 2) { // test getPreviousNDays method int n = 0; year = Integer.parseInt(input.next()); month = Integer.parseInt(input.next()); day = Integer.parseInt(input.next()); DateUtil date = new DateUtil(year, month, day); if (!date.checkInputValidity()) { System.out.println("Wrong Format"); System.exit(0); } n = input.nextInt(); if (n < 0) { System.out.println("Wrong Format"); System.exit(0); } System.out.print( date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:"); System.out.println(date.getPreviousNDays(n).showDate()); } else if (choice == 3) { //test getDaysofDates method year = Integer.parseInt(input.next()); month = Integer.parseInt(input.next()); day = Integer.parseInt(input.next()); int anotherYear = Integer.parseInt(input.next()); int anotherMonth = Integer.parseInt(input.next()); int anotherDay = Integer.parseInt(input.next()); DateUtil fromDate = new DateUtil(year, month, day); DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay); if (fromDate.checkInputValidity() && toDate.checkInputValidity()) { System.out.println("The days between " + fromDate.showDate() + " and " + toDate.showDate() + " are:" + fromDate.getDaysofDates(toDate)); } else { System.out.println("Wrong Format"); System.exit(0); } } else{ System.out.println("Wrong Format"); System.exit(0); } } }
自己依照7-3依葫芦画瓢画类图

在做这一题的时候,认真看了主函数的编写,就发现了前几题自己出现的问题,调用带参的构造方法,new一个对象,而不是像做第三题一样,调用不带参的构造方法,再利用setter将值传入,相比之下自己的做法显得非常无知且低效。
对于求下n天和前n天,我的做法是将现在的天数和n值直接相加或相减,然后依次减去或加上相继月份的天数,到天数之和不足一个月的天数或大于0时为止。但在提交过程中发现,下n天:整型数最大值测试,这一测试点没通过,而前n天:整型数最小值和最大值测试都通过了。思考后发现,求前n天时是天数相减,差值在int类型的范围内,而求下n天时,由于天数相加,一个整数再加上int类型的最大值就超出了int类型的最大值。于是先行做了个判断,如果n值大于这个月的最大天数,就先减去这个月的最大天数,月份加一,然后再与天数day相加,这样就能确保相加的和在int类型的取值范围内。
对于求两个日期的相差的天数,起初我是在判断日期不相同后,先计算年的差值,再计算月和天的差值,判断后相加或相减求天数,如果是闰年就增加366天,如果是平年就增加365天。在提交的过程中测试点都没过,结果相差较多。思考后发现,如果当年是闰年,但给定的日期已经超过了2月份,即使是过了一整年,相差的天数也只是365天而不是366天,如果采用这种方法的话,判断的条件就需要增加较多。于是换了一种思路,将相差的年数全部转化为月份的数量,然后和求前n天类似的方法去加上每个月的最大天数,这样就不需要担心给定的日期是在2月份之前还是之后。到年份和月份相同时跳出循环,再判断日期是否相同,如果否,只需要再计算两个日期间day的差值,再相加即可。
再说一下做这道题时碰到的一个疑惑点,看到 public DateUtil getNextNDays(int n);//取得year-month-day的下n天日期 和 public DateUtil getPreviousNDays(int n);//取得year-month-day的前n天日期 这两个方法时,对于类名做类型感到很奇怪,不知道返回什么。通过搜索查询和询问同学后得知,以类名为方法类型的时候需要将这个类的对象返回。所以在这两个方法中都利用带参的构造方法new了一个新对象,再将对象返回。
需要的改进:再次审题发现,判断日期是否相等时,并没有判断两个日期的前后,测试点中的数值应该也是默认前面输入的日期更前,后面输入的日期更后。如果日期交换顺序,那么所的结果就会完全不同。因此,如果要完善这漏洞的话,需要在计算日期相差天数时再增加判断日期前后的条件,计算时能够交换日期的顺序或者再写一种以后面的日期为准向前计算的方法。
总结:
初学Java,相对于c语言的初步学习,有明显的难度提升,在课堂上精讲的东西不多,更依赖自我学习能力。通过三次练习,对基础语法,类、方法的设计有了更清晰的认识,比如判断、循环语句的使用,目前阶段来说这些基础语法和c语言差距不太明显。再比如反复提及的带参的构造方法,无参的构造方法,虽然基础,而且在课上虽然老师具体讲了一遍,但在写7-3和7-4两题时还是比较困难,不能很好的使用和理解,但在看过7-4题目所给的主方法和通过自己查询有关介绍后,有一个更深刻的理解,以及对于代码的规范编写也有一个更丰富的认识。另外,在练习中发现,Java还有很多基础知识并不清晰,比如对类中方法的调用,通过new创建一个新对象等,还需要主动的学习有关知识,加深理解和记忆。
一点建议:
个人觉得7-4一题中题目所给的主函数Main对代码的规范编写,带参的构造方法,无参的构造方法的理解和题意上的理解很有帮助,(老师可以交换7-3和7-4题目的顺序)可以选择先做或者先看7-4再来完成7-3,会极大提高7-3代码编写的准确率和规范性。如果觉得7-3和7-4难度差距比较大直接交换题目顺序不太好的话,可以将调整两道题的难度或者以第四题这种形式来写第三题,然后将类图放在第四题,因为我个人觉得类图比7-4直接给出方法名称和作用这种形式更难理解。
在7-4中,计算两个日期相差天数的测试点只有一个,且数据好像默认了前面输入的日期更前,希望能增加一个计算日期相差天数的测试点,将前面输入的日期设置为较后的日期。

浙公网安备 33010602011771号