OOP训练集1~3总结
一、前言
OOP训练集的三次作业题量一共25题,第一次作业考察的知识点主要是Java程序的基本语法,基本的输入类Scanner的用法、各类型变量定义的方法、if...else语句、System.out.println()和System.out.printf()和System.out.print()的用法、charAt()返回字符的用法、indexOf()查找关键字符串等。第二次作业相较第一次作业难度有所减小,考察的知识点也基本相同。第三次作业相较前两次作业难度提升较大,虽然只有4题,但每题都有一定的难度,其考察的知识点有private私有性变量的使用方法、类的构造方法和使用方法,其使用的Java语法并不算很难,其主要难度体现在算法的设计上。
二、设计与分析
详细的分析在注解中,小结则为该题的一些概括说明
基本年利率7.7%
- 如果一年以内利率给5折
- 如果三年以内利率为7折
- 如果五年以内利率为100%
- 如果五年以上利率为1.1倍
输入一个年份,计算这个年份下的实际利率是多少?
输入格式:
输入一个整数。
输出格式:
实际利率=x.xx%
输入样例1:
6
输出样例1:
实际利率=8.47%
输入样例2:
-1
输出样例2:
error
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner input=new Scanner(System.in); int n=0;//n为年数 double cent=0; n=input.nextInt(); if(n>0 && n<=1){ cent=7.7 * 0.5 ; System.out.println("实际利率="+cent+"%"); } else if(n>1 && n<=3){ cent=7.7 * 0.7 ; System.out.println("实际利率="+cent+"%"); } else if(n>3 && n<=5){ cent=7.7; System.out.println("实际利率="+cent+"0%"); } else if(n>5){ cent=7.7 * 1.1 ; System.out.println("实际利率="+cent+"%"); } else if(n<=0) System.out.println("error"); } }
小结:该题难度并不大,只需要注意一下输出格式即可。
体重是反映和衡量一个人健康状况的重要标志之一,过胖和过瘦都不利于健康,BMI(身体质量指数)计算方法:体重(以千克为单位)除以身高(以米为单位)的平方。中国成人正常的BMI应在18.5-24之间,如果小于18.5为体重不足,如果大于等于24为超重,大于等于28为肥胖。请编写程序,测算身体状态。
输入格式:
两个数值:体重(以千克为单位),身高(以米为单位),数值间以空格分隔。例如:65.5 1.75。
注意:体重的世界纪录是727公斤,身高的世界纪录是2.72米。输入数据上限不得超过纪录,下限不得小于等于0;
输出格式:
输入数值超出范围 :输出“input out of range”。例如:-2 3或者125 5。
BMI小于18.5 :输出“thin”。
BMI大于等于18.5小于24 :输出“fit”。
BMI大于等于24小于28 :输出“overweight”。
BMII大于等于28 :输出“fat”。
输入样例0:
在这里给出一组输入。例如:
-2 8
输出样例0:
在这里给出相应的输出。例如:
input out of range
输入样例1:
在这里给出一组输入。例如:
70 1.75
输出样例1:
在这里给出相应的输出。例如:
fit
import java.util.Scanner; public class Main { public static void main(String[] args){ float height = 0 ; float weight = 0 ; float BMI = 0; Scanner input = new Scanner(System.in); weight = input.nextFloat(); height = input.nextFloat(); if( height > 0 && height <= 2.72 && weight >0 && weight <= 727 ) { BMI = weight / ( height * height ); if(BMI<18.5) System.out.println("thin"); else if(BMI>=18.5&&BMI<24) System.out.println("fit"); else if(BMI>=24&&BMI<28) System.out.println("overweight"); else if(BMI>=28) System.out.println("fat"); } else System.out.println("input out of range"); } }
小结:只需要几条if...else语句便可搞定
打印九九乘法表,乘法表格式如图。

接收用户从键盘输入的一个1到9(含边界)的整数,假设该整数是n,则打印乘法表的前n行。
说明:
(1)用户输入的整数不在1到9这个范围内,则固定输出下面信息:
INPUT ERROR.
(2)两个整数之间的乘号,是使用的大写字母X。同一行的多个乘法结果之间,用制表符\t分开,一行末尾没有多余的制表符。
输入格式:
一个整数n。
输出格式:
乘法表的前n行。
输入样例1:
如用户输入16。
16
输出样例1:
提示用户输入的数据有误。
INPUT ERROR.
输入样例2:
如用户输入3,打印乘法表前3行。
3
输出样例2:
提示用户输入的数据有误。
1X1=1
2X1=2 2X2=4
3X1=3 3X2=6 3X3=9
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner input = new Scanner(System.in); int n = 0; int i = 1; n = input.nextInt(); if( n > 9 || n < 1 ) System.out.println("INPUT ERROR."); else{ for( ; i<=n ; i++ ) for(int j = 1 ; j <= i ; j++ ){ System.out.print(i+"X"+j+"="+i*j); if(j!=i) System.out.print("\t"); else System.out.print("\n"); } } } }
小结:语法部分不难,难在输出格式和算法设计部分
有一快递公司,运费计算规则如下:
首重(1.0kg)12.0元,续重2.0元/kg
首重(20.0kg)39.0元,续重1.9元/kg
首重(60.0kg)115.0元,续重1.3元/kg
输入物体的重量,计算应付的运费,四舍五入保留整数。
注:建议采用int(x+0.5)
输入格式:
输入物体的重量
输出格式:
输出运费,四舍五入保留整数
输入样例1:
在这里给出一组输入。例如:
2
输出样例1:
在这里给出相应的输出。例如:
14
输入样例2:
在这里给出一组输入。例如:
21
输出样例2:
在这里给出相应的输出。例如:
41
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner input = new Scanner(System.in); double weight = 0 ; double price = 0 ; int priceint = 0 ; weight=input.nextDouble(); if( weight > 0 && weight <= 1 ) System.out.println("12"); else if( weight > 1 && weight < 20){ price = 12.5+2*(weight-1) ; priceint = (int)price; System.out.println(priceint); } else if( weight >= 20 && weight < 60 ){ price = 39.5+1.9*(weight-20); priceint = (int)price; System.out.println(priceint); } else if( weight >= 60 ){ price = 115.5+1.3*(weight-60); priceint = (int)price; System.out.println(priceint); } } }
小结:输出格式需注意
输入一个字符串,输出将其中重复出现的字符去掉后的字符串
输入格式:
一行字符串
输出格式:
去掉重复字符后的字符串
输入样例:
在这里给出一组输入。例如:
ofiweirowqrigu
输出样例:
在这里给出相应的输出。例如:
ofiwerqgu
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner input=new Scanner(System.in); String s; s=input.nextLine(); StringBuilder modify = new StringBuilder(s); for(int i=0;i<s.length();i++) for(int j=i+1;j<s.length();j++){ if(s.charAt(i)==s.charAt(j)){ for(int k=j;k<s.length();k++){ if(k!=s.length()-1) modify.setCharAt(k,s.charAt(k+1)); else modify.setCharAt(k,'\0'); } s = modify.toString(); } } System.out.println(s); } }
小结:该题需要用到StringBuilder变量,是一个难点,因为String类型的变量在赋值后不可更改,除此之外,算法的设计也较难,初次接触需要一定时间
一、定积分的概念




根据以上理论,求定积分:
输入格式:
输入定积分下限,定积分上限,区间[a,b]被分割的份数。
输出格式:
输出定积分的值,保留4位小数。
输入样例:
1 2 100
输出样例:
2.3334
1 import java.util.Scanner; 2 public class Main { 3 4 public static void main(String[] args){ 5 Scanner input=new Scanner(System.in); 6 double sum=0; 7 double a=0,b=0; 8 double n=0; 9 a = input.nextDouble(); 10 b = input.nextDouble(); 11 n = input.nextDouble(); 12 for( int i=1 ; i<=n ; i++ ){ 13 sum+=(a+(i-0.5)*((b-a)/n))*(a+(i-0.5)*((b-a)/n))*((b-a)/n); 14 } 15 System.out.printf("%.4f\n",sum); 16 } 17 }
小结:该题全部代码较为简单,语法与算法设计并不难,需要注意的是输出格式和分割方法。
NMEA-0183协议是为了在不同的GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA-The National Marine Electronics Associa-tion)制定的一套通讯协议。GPS接收机根据NMEA-0183协议的标准规范,将位置、速度等信息通过串口传送到PC机、PDA等设备。
NMEA-0183协议是GPS接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接收机、GPS数据处理软件、导航软件都遵守或者至少兼容这个协议。
NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL等。
其中$GPRMC语句的格式如下:
$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
这里整条语句是一个文本行,行中以逗号“,”隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。
- 字段0:
$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息 - 字段1:UTC时间,hhmmss.sss格式
- 字段2:状态,A=定位,V=未定位
- 字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
- 字段4:纬度N(北纬)或S(南纬)
- 字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
- 字段6:经度E(东经)或W(西经)
- 字段7:速度,节,Knots
- 字段8:方位角,度
- 字段9:UTC日期,DDMMYY格式
- 字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
- 字段11:磁偏角方向,E=东W=西
- 字段16:校验值
这里,*为校验和识别符,其后面的两位数为校验和,代表了$和*之间所有字符(不包括这两个字符)的异或值的十六进制值。上面这条例句的校验和是十六进制的50,也就是十进制的80。
提示:^运算符的作用是异或。将$和*之间所有的字符做^运算(第一个字符和第二个字符异或,结果再和第三个字符异或,依此类推)之后的值对65536取余后的结果,应该和*后面的两个十六进制数字的值相等,否则的话说明这条语句在传输中发生了错误。注意这个十六进制值中是会出现A-F的大写字母的。另外,在Java语言中,如果你需要的话,可以用Integer.parseInt(s)从String变量s中得到其所表达的整数数字;而Integer.parseInt(s, 16)从String变量s中得到其所表达的十六进制数字
现在,你的程序要读入一系列GPS输出,其中包含$GPRMC,也包含其他语句。在数据的最后,有一行单独的
END
表示数据的结束。
你的程序要从中找出$GPRMC语句,计算校验和,找出其中校验正确,并且字段2表示已定位的语句,从中计算出时间,换算成北京时间。一次数据中会包含多条$GPRMC语句,以最后一条语句得到的北京时间作为结果输出。
你的程序一定会读到一条有效的$GPRMC语句。
输入格式:
多条GPS语句,每条均以回车换行结束。最后一行是END三个大写字母。
输出格式:
6位数时间,表达为:
hh:mm:ss
其中,hh是两位数的小时,不足两位时前面补0;mm是两位数的分钟,不足两位时前面补0;ss是两位数的秒,不足两位时前面补0。
输入样例:
$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
END
输出样例:
10:48:13
1 import java.util.Scanner; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 Scanner input = new Scanner(System.in); 7 String time = "" ;// 进行初始化,防止编译出错 8 String GPS = input.nextLine(); 9 10 while( !GPS.equals("END") )// 输入为END ,结束输入 11 { 12 String[] GPSinfo = GPS.split(",");// 去除所有逗号后的信息存入GPSinfo 13 14 if(!GPSinfo[0].equals("$GPRMC"))// 如果第一个逗号以前的部分不为所要求,读入下一列,结束这一行处理 15 { 16 GPS = input.nextLine(); 17 continue; 18 } 19 int i , SUM = 0 ; 20 char ch; 21 22 ch = GPS.charAt(1);// 进行异或运算 23 for( SUM = (int)GPS.charAt(1) , i = 2 ; ch != '*' ; i++ , ch = GPS.charAt(i) ) 24 { 25 ch = GPS.charAt(i) ; 26 SUM^= (int)ch ; 27 } 28 SUM %= 65536 ; 29 String check = GPS.substring(i+1, i+3);// 得到校验值 30 31 char status = GPSinfo[2].charAt(0); 32 check = check.toLowerCase() ;// 转化为小写,因为Integer.toHexString()转换出的十六进制字符串的字母为小写 33 if( check.equals(Integer.toHexString(SUM)) && status == 'A' )// 如果相同 且 状态为A 34 time = GPSinfo[1]; 35 GPS = input.nextLine();// 以最后一条进行输出 36 } 37 38 String hh = time.substring(0, 2); 39 int hour = Integer.parseInt(hh); 40 hour = ( hour + 8 ) % 24 ; 41 if( hour < 10 )// 调整输出模式 42 System.out.print(0); 43 System.out.print( hour + ":" + time.substring(2, 4) + ":" + time.substring(4, 6) ); 44 } 45 }
SourceMonitor分析结果:

小结:由SourceMonitor的分析结果得知,虽然该题用到类和方法不多,但代码还是较为复杂的,说明在算法的设计上,这题要求很严格。在解本道题的时候,也确实花费了很多很多的时间去设计算法,在设计过程也碰到了很多问题,
例如非零返回,这个是最烦人的,在编译器Eclipse中,即使是非零返回也依旧可能不会报错继续执行程序,输出的结果也会显示正确,在思考多日无果后便去查阅了一些资料才将此bug得以修复。
OOP训练集02:训练集02相较训练集01稍微简单,这里只挑两道较难的题目进行出来分析
输入三角形三条边,判断该三角形为什么类型的三角形。
输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[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”。
输入样例1:
在这里给出一组输入。例如:
50 50 50.0
输出样例1:
在这里给出相应的输出。例如:
Equilateral triangle
输入样例2:
在这里给出一组输入。例如:
60.2 60.2 80.56
输出样例2:
在这里给出相应的输出。例如:
Isosceles triangle
输入样例3:
在这里给出一组输入。例如:
0.5 20.5 80
输出样例3:
在这里给出相应的输出。例如:
Wrong Format
1 import java.util.*; 2 3 public class Main{ 4 public static void main(String[] args){ 5 Scanner input = new Scanner(System.in) ; 6 float a = 0 ;// 三边之一 7 float b = 0 ;// 三边之一 8 float c = 0 ;// 三边之一 9 a = input.nextFloat() ; 10 b = input.nextFloat() ; 11 c = input.nextFloat() ; 12 if( a>=1 && a<=200 && b>=1 && b<=200 && c>=1 && c<=200 ){ 13 if( Math.abs(a-b)<c && Math.abs(a-c)<b && Math.abs(b-c)<a ){ 14 if( a==b && b==c ){ 15 System.out.println("Equilateral triangle");// 等边三角形 16 } 17 else if( a==b || a==c || b==c ){ 18 // 等腰直角三角形输入带根号2的近视值会造成误差,判断无法相等,当误差在一定范围内认为相等 19 if( Math.abs(a*a+b*b-c*c)<=0.001 || Math.abs(a*a+c*c-b*b)<=0.001 || Math.abs(c*c+b*b-a*a)<=0.001 ) 20 System.out.println("Isosceles right-angled triangle");// 等腰直角三角形 21 else 22 System.out.println("Isosceles triangle");// 等腰三角形 23 } 24 else if( a*a + b*b == c*c || a*a + c*c == b*b || b*b + c*c == a*a ){ 25 System.out.println("Right-angled triangle");// 直角三角形 26 } 27 else{ 28 System.out.println("General triangle");// 一般三角形 29 } 30 } 31 else 32 System.out.println("Not a triangle");// 不能构成三角形 33 } 34 else 35 System.out.println("Wrong Format");// 数据非法 36 } 37 }
SourceMonitor分析结果:

小结:从SourceMonitor的分析结果来看,我个人设计的代码比较复杂,也许是因为用的if...else语句太多,这也体现了我个人在编程方面能力还很欠缺,有待进步。此题需要注意的一点就是直角三角形的判定,因为计算机无法输入完全精
确的数字,永远都是接近,所以在一些长度大小带根号的边的三角形中通过计算机的计算会存在一些误差,因此直角三角形的判断语句应该是两直角边平方之和与第三边平方的差小于某一很小的数,这样才能较为精确地判断直角
三角形。这里本人的代码还存在一个不足,就是在普通直角三角形的判断那依旧是完全相等,但是PTA也通过了,说明PTA的分数评判不完全准确,要让自己的代码更完美需要自己深度测试和深度思考。
输入年月日的值(均为整型数),输出该日期的下一天。 其中:年份的合法取值范围为[1820,2020] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。
注意:不允许使用Java中和日期相关的类和方法。
要求:Main类中必须含有如下方法,签名如下:
public static void main(String[] args);//主方法
public static boolean isLeapYear(int year) ;//判断year是否为闰年,返回boolean类型
public static boolean checkInputValidity(int year,int month,int day);//判断输入日期是否合法,返回布尔值
public static void nextDate(int year,int month,int day) ; //求输入日期的下一天
输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
输出格式:
- 当输入数据非法及输入日期不存在时,输出“Wrong Format”;
- 当输入日期合法,输出下一天,格式如下:Next date is:年-月-日
输入样例1:
在这里给出一组输入。例如:
2020 3 10
输出样例1:
在这里给出相应的输出。例如:
Next date is:2020-3-11
输入样例2:
在这里给出一组输入。例如:
2025 2 10
输出样例2:
在这里给出相应的输出。例如:
Wrong Format
1 import java.util.*; 2 public class Main{ 3 //主函数 4 public static void main(String[] args){ 5 Scanner input = new Scanner(System.in) ; 6 int year = 0 ; 7 int month = 0 ; 8 int day = 0 ; 9 year = input.nextInt(); 10 month = input.nextInt(); 11 day = input.nextInt(); 12 if( checkInputValidity( year , month , day) == true ) 13 nextDate( year , month , day ) ; 14 else 15 System.out.println("Wrong Format") ; 16 input.close();// 关闭输入源 17 } 18 //判断闰年 19 public static boolean isLeapYear( int year ){ 20 if( year%400==0 ) 21 return true ; 22 else if( year%4==0 ){ 23 if( year%100==0 ) 24 return false ; 25 else 26 return true ; 27 } 28 else 29 return false ; 30 } 31 //判断日期是否合法 32 public static boolean checkInputValidity(int year,int month,int day){ 33 if( year>=1820 && year<=2020 && month>=1 && month<=12 && day>=1 && day<=31 ) 34 return true; 35 else 36 return false; 37 } 38 //计算 39 public static void nextDate(int year,int month,int day){ 40 if( month==1 || month==3 || month==5 || month==7 || month==8 || month==10 ){ 41 if( day==31 ){// 这几个月份共有31天 42 month+=1 ; 43 day = 1 ; 44 } 45 else{ 46 day+=1 ; 47 } 48 System.out.println("Next date is:"+year+"-"+month+"-"+day) ; 49 } 50 else if( month==12 ){// 12月可能会存在下一天就是下一年的情况,单独做一个if语句 51 if( day==31 ){ 52 year+=1 ; 53 month = 1 ; 54 day = 1 ; 55 } 56 else{ 57 day+=1 ; 58 } 59 System.out.println("Next date is:"+year+"-"+month+"-"+day) ; 60 } 61 else if( month==4 || month==6 || month==9 || month==11 ){ 62 if( day==30 ){// 这几个月份共有30天 63 month+=1 ; 64 day = 1 ; 65 } 66 else{ 67 day+=1 ; 68 } 69 System.out.println("Next date is:"+year+"-"+month+"-"+day) ; 70 } 71 else if( month==2 ){// 2月可能有28天,也可能有29天,特殊情况多做一个if语句 72 if( isLeapYear( year )==true ){// 闰年,说明有29天 73 if( day==29 ){ 74 month+=1 ; 75 day = 1 ; 76 } 77 else{ 78 day+=1 ; 79 } 80 System.out.println("Next date is:"+year+"-"+month+"-"+day) ; 81 } 82 else{ 83 if( day==28 ){// 闰年,说明有28天 84 month+=1 ; 85 day = 1 ; 86 System.out.println("Next date is:"+year+"-"+month+"-"+day) ; 87 } 88 else if( day<=28 ){ 89 day+=1 ; 90 System.out.println("Next date is:"+year+"-"+month+"-"+day) ; 91 } 92 else 93 System.out.println("Wrong Format") ; 94 } 95 } 96 } 97 }
SourceMonitor分析结果:

小结:从SourceMonitor的分析结果和我OOP老师的评价来看,我这一坨代码就是屎山代码,完全不合格,非常复杂,if...else语句用的太多,可读性低,虽然在逻辑上没有问题,但是就从程序可读性来讲,这串代码就是一堆屎山。虽然
如此,但是因为按照这样的一个算法逻辑走下去来设计,思路非常清晰,在解题的时候并没有花费太长时间,很轻松,唯一的一个稍微有难度的就是闰年和非闰年2月下一天会不会是3月1号。
OOP训练集03:最难的一次作业,这里会对四道题都进行分析与小结
编写一个圆形类Circle,一个私有实型属性半径,要求写出带参数构造方法、无参构造方法、属性的getter、setter方法以及求面积、输出数据等方法,具体格式见输入、输出样例。
输入格式:
在一行内输入一个实型数作为圆的半径(半径数值要求不能为负值)
输出格式:
-
如果半径输入非法,则直接输出
Wrong Format -
如果输入半径合法,则输出如下两行数据
The circle's radius is:圆的半径值The circle's area is:圆的面积值要求输出数据均保留2位小数,PI的取值使用Math.PI。
输入样例:
在这里给出一组输入。例如:
-5
输出样例:
在这里给出相应的输出。例如:
Wrong Format
输入样例:
在这里给出一组输入。例如:
2.5
输出样例:
在这里给出相应的输出。例如:
The circle's radius is:2.50
The circle's area is:19.63
1 import java.util.*; 2 3 public class Main{ 4 5 public static void main(String[] args){ 6 Scanner input = new Scanner(System.in) ; 7 double r = input.nextDouble() ; 8 if( r<0 )// 非法输入 9 System.out.println("Wrong Format") ; 10 else{ 11 Circle test = new Circle() ; 12 test.setradius(r) ; 13 System.out.printf("The circle's radius is:%.2f\n",test.getradius() ) ; 14 System.out.printf("The circle's area is:%.2f\n",test.getarea() ) ; 15 } 16 } 17 18 } 19 20 21 class Circle{ 22 private double radius ;// 半径 23 double area ;// 面积 24 25 public void setradius( double r ){ //setter给私有实型半径赋值 26 radius = r ; //给半径赋值 27 } 28 29 public double getradius(){ //getter返回半径值 30 return radius ; 31 } 32 33 public double getarea(){ //求面积 34 area = radius*radius*Math.PI ; 35 return area ; 36 } 37 38 }
SourceMonitor分析结果:

小结:从SourceMonitor的分析结果来看,此题代码并不复杂,结合本人做题的感受也是如此。个人认为此题只是让我们能够熟悉类的构造方法和使用方法以及私有性private的使用方法。
设计一个名称为Account的类,具体包括:
- id:账号,私有属性,整型,默认值为0;
- balance:余额,私有属性,实型,默认值为0;
- annualInterestRate:当前利率,私有属性,实型,默认值为0,假设所有帐户均有相同的利率;
- dateCreated:账户开户时间,私有属性,LocalDate类型,默认为2020年7月31日;
- 一个能创建默认账户的无参构造方法;
- 一个能创建带特定id和初始余额的账户的构造方法;
- id、balance、annualInterstRate的getter及setter方法;
- dateCreated的getter方法;
- 一个名为getMonthlyInterestRate()的方法返回月利率(月利率计算公式:余额*(年利率/1200));
- 一个名为withDraw的方法从账户提取特定数额,当提取数额大于余额或为负数系统返回
WithDraw Amount Wrong提示; - 一个名为deposit的方法向账户存储特定数额,当存储数额大于20000元或为负数系统返回
Deposit Amount Wrong提示。
编写一个测试程序:
- 创建一个账户,其账户id、余额及利率分别有键盘输入,账户开户时间取系统当前时间;
- 输入取钱金额,系统进行取钱操作,如果取钱金额有误,则输出提示信息后系统继续运行;
- 输入存钱金额,系统进行存钱操作,如果存钱金额有误,则输出提示信息后系统继续运行;
- 系统输出,以如下格式分别输出该账户余额、月利息以及开户日期(输出实型数均保留两位小数)
输入格式:
在一行内分别输入账户id、初始余额、当前利率、提取金额、存储金额,数据间采用一个或多个空格分隔。
输出格式:
共分三行输出,分别为约、计算的月利息以及开户日期,格式如下:
-
The Account'balance:余额 The Monthly interest:月利息The Account'dateCreated:年-月-日
输入样例1:
在这里给出一组输入。例如:
1122 20000 0.045 800 600
输出样例1:
在这里给出相应的输出。例如:
The Account'balance:19800.00
The Monthly interest:0.74
The Account'dateCreated:2020-07-31
输入样例2:
在这里给出一组输入。例如:
1122 20000 0.045 8000 30000
输出样例2:
在这里给出相应的输出。例如:
Deposit Amount Wrong
The Account'balance:12000.00
The Monthly interest:0.45
The Account'dateCreated:2020-07-31
1 import java.time.LocalDate; 2 import java.util.Scanner; 3 4 public class Main{ 5 public static void main(String[] ars){ 6 Account account = new Account() ;// 创建一个新的Account对象 7 account.repeat() ;// 调用方法 8 } 9 } 10 11 class Account{ 12 private int id ;// 账号 13 private double balance = 0 ;// 余额 14 private double annualInterestRate = 0 ;// 当前利率 15 private LocalDate date ;// 开户时间 16 private double MonthlyInterestRate ;// 月利率 17 //设置id 18 public void setid( int id ){ 19 if( id>0 ) 20 this.id = id ; 21 } 22 //设置balance 23 public void setbalance( double balance , double withdraw , double deposit ){ 24 if( balance>=0 ){ 25 if( withDraw(balance,withdraw)==true && Deposit(balance,deposit)==true ) 26 this.balance = balance-withdraw+deposit ; 27 else if( withDraw(balance,withdraw)==true && Deposit(balance,deposit)==false ){ 28 this.balance = balance-withdraw ; 29 System.out.println("Deposit Amount Wrong") ; 30 31 } 32 else if( Deposit(balance,deposit)==true && withDraw(balance,withdraw)==false ){ 33 this.balance = balance+deposit ; 34 System.out.println("WithDraw Amount Wrong") ; 35 } 36 else{ 37 System.out.println("WithDraw Amount Wrong") ; 38 System.out.println("Deposit Amount Wrong") ; 39 this.balance = balance ; 40 } 41 } 42 } 43 //设置annualInterestRate 44 public void setannualInterestRate( double annualInterestRate ){ 45 if( annualInterestRate>0 ) 46 this.annualInterestRate = annualInterestRate ; 47 } 48 //获得id 49 public int getid(){ 50 return this.id ; 51 } 52 //获得balance 53 public double getbalance(){ 54 return this.balance ; 55 } 56 //获得annualInterestRate 57 public double getannualInterestRate(){ 58 return this.annualInterestRate ; 59 } 60 //获得月利率 61 public double getMonthlyInterestRate(){ 62 this.MonthlyInterestRate = balance*(annualInterestRate/1200) ; 63 return this.MonthlyInterestRate ; 64 } 65 //无参数创建默认账户 66 public void idCreated1(){ 67 this.date = LocalDate.of(2020,7,31) ; 68 this.id = 0 ; 69 } 70 //能创建带特定id和初始余额的账户的构造方法 71 public void idCreated2( int id , double balance , double annualInterestRate , double withdraw , double deposit ){ 72 setid( id ) ; 73 setbalance(balance,withdraw,deposit) ; 74 setannualInterestRate( annualInterestRate ) ; 75 this.MonthlyInterestRate = getMonthlyInterestRate() ; 76 this.date = LocalDate.of(2020,7,31);// 测试节点均为默认时间 77 } 78 79 public boolean withDraw( double balance , double withdraw ){ 80 if( withdraw>balance || withdraw<0 ){ 81 return false ;//防止忽略返回值 82 } 83 else 84 return true ; 85 } 86 87 public boolean Deposit( double balance , double deposit ){ 88 if( deposit>20000 || deposit<0 ){ 89 return false ;//防止忽略返回值 90 } 91 else 92 return true ; 93 } 94 95 public void repeat(){// 可反复调用,但此题测试没有重复调用的用例 96 int id ; 97 double balance ; 98 double annualInterestRate ; 99 double withdraw ; 100 double deposit ; 101 Scanner input = new Scanner(System.in) ; 102 id = input.nextInt() ; 103 balance = input.nextDouble() ; 104 annualInterestRate = input.nextDouble() ; 105 withdraw = input.nextDouble() ; 106 deposit = input.nextDouble() ; 107 idCreated2( id , balance , annualInterestRate , withdraw , deposit ) ; 108 System.out.printf("The Account'balance:%.2f\n",this.balance) ; 109 System.out.printf("The Monthly interest:%.2f\n",this.MonthlyInterestRate) ; 110 System.out.println("The Account'dateCreated:"+this.date) ; 111 } 112 }
SourceMonitor分析结果:

小结:从SourceMonitor的分析结果来看,该题代码总体复杂度并不高,但同时评价也不高,中规中矩。个人认为此题难度适中,不高不低。主要的难点还是对类的构造方法和使用方法不怎么熟悉,以及对构造非无类型函数不熟练,
在使用if语句后总是会出现漏返回值的情况,导致非零返回。同时,在这题中又多接触到了一个新的类型LocalDate,是专门用来定义时间变量的。
定义一个类Date,包含三个私有属性年(year)、月(month)、日(day),均为整型数,其中:年份的合法取值范围为[1900,2000] ,月份合法取值范围为[1,12] ,日期合法取值范围为[1,31] 。
注意:不允许使用Java中和日期相关的类和方法,否则按0分处理。
要求:Date类结构如下图所示:

输入格式:
在一行内输入年月日的值,均为整型数,可以用一到多个空格或回车分隔。
输出格式:
- 当输入数据非法及输入日期不存在时,输出“Date Format is Wrong”;
- 当输入日期合法,输出下一天,格式如下:Next day is:年-月-日
输入样例1:
在这里给出一组输入。例如:
1912 12 25
输出样例1:
在这里给出相应的输出。例如:
Next day is:1912-12-26
输入样例2:
在这里给出一组输入。例如:
2001 2 30
输出样例2:
在这里给出相应的输出。例如:
Date Format is Wrong
1 import java.util.*; 2 3 public class Main{ 4 5 public static void main(String[] args){ 6 Scanner input = new Scanner(System.in) ; 7 int year = input.nextInt() ; 8 int month = input.nextInt() ; 9 int day = input.nextInt() ; 10 Date date = new Date() ;// 创建一个新的Date类 11 date.Date( year , month , day ) ; 12 } 13 14 15 } 16 17 class Date{ 18 private int year ; 19 private int month ; 20 private int day ; 21 protected int mon_maxnun[] =new int[] {0,31,28,31,30,31,30,31,31,30,31,30,31};// 用于存储各个月份的天数 22 23 public int Date( int year , int month , int day ){// 设置日期 24 setYear( year ) ; 25 setMonth( month ) ; 26 setDay( day ) ; 27 getNextDate() ; 28 return 1; 29 } 30 31 public int getYear(){// 得到年份 32 return this.year ; 33 } 34 35 public void setYear( int year ){// 设置年份 36 this.year = year ; 37 } 38 39 public int getMonth(){// 得到月份 40 return this.month ; 41 } 42 43 public void setMonth( int month ){// 设置月份 44 this.month = month ; 45 } 46 47 public int getDay(){// 得到天数 48 return this.day ; 49 } 50 51 public void setDay( int day ){// 设置日期 52 this.day = day ; 53 } 54 55 public boolean isLeapYear( int year ){// 判断闰年 56 if( year%4==0 ){ 57 if( year%100==0 ){ 58 if( year%400==0 ) 59 return true ; 60 else 61 return false ; 62 } 63 else 64 return true ; 65 } 66 else 67 return false ; 68 } 69 70 public boolean checkInputValidity(){// 检查输入日期是否合法 71 if( this.year>=1900 && this.year<=2000 && this.month>=1 && this.month<=12 ){// 是否合法的条件 72 if( this.month == 2 ){// 2月份情况 73 if( isLeapYear( this.year )==true ){ 74 if( this.day>=1 && this.day<=29 ) 75 return true ; 76 else 77 return false ; 78 } 79 else if( this.day>=1 && this.day<=28 ) 80 return true ; 81 else 82 return false ; 83 } 84 else if( getMonth()==1 || getMonth()==3 || getMonth()==5 || getMonth()==7 || getMonth()==8 || getMonth()==10 || getMonth()==12 ){ 85 if( this.day>=1 && this.day<=31 )// 31天月份情况 86 return true ; 87 else 88 return false ; 89 } 90 else{ 91 if( this.day>=1 && this.day<=30 )// 30天月份情况 92 return true ; 93 else 94 return false ; 95 } 96 } 97 else 98 return false ; 99 } 100 101 public void getNextDate(){ 102 if( checkInputValidity()==false ){ 103 System.out.println("Date Format is Wrong"); 104 } 105 else{ 106 if( mon_maxnun[getMonth()]==getDay() ){// 说明要进入下一个月或者下一年 107 if( getMonth()==12 ){// 12月 108 System.out.println("Next day is:"+(getYear()+1)+"-1-1"); 109 } 110 else{ 111 System.out.println("Next day is:"+getYear()+"-"+(getMonth()+1)+"-1"); 112 } 113 } 114 else{ 115 if( getMonth()==2 && getDay()==29 )// 闰年的2月份 116 System.out.println("Next day is:"+getYear()+"-"+(getMonth()+1)+"-1"); 117 else// 普通情况,直接给日加1 118 System.out.println("Next day is:"+getYear()+"-"+getMonth()+"-"+(getDay()+1)); 119 } 120 } 121 } 122 }
SourceMonitor分析结果:

小结:从SourceMonitor的分析结果来看,该题的代码设计的较为复杂,质量较低,还有待改进。该题与OOP训练集02是同一个问题的不同形式,02中没对是否要做Date类做要求,可以将算法全部写入主类中。总体难度与02最后一题差
不多,只能说是这题的难点在于该如何构造一个类,怎么使用它,两题算法是几乎一致的。
参考题目3和日期相关的程序,设计一个类DateUtil,该类有三个私有属性year、month、day(均为整型数),其中,year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 除了创建该类的构造方法、属性的getter及setter方法外,需要编写如下方法:
public boolean checkInputValidity();//检测输入的年、月、日是否合法
public boolean isLeapYear(int year);//判断year是否为闰年
public DateUtil getNextNDays(int n);//取得year-month-day的下n天日期
public DateUtil getPreviousNDays(int n);//取得year-month-day的前n天日期
public boolean compareDates(DateUtil date);//比较当前日期与date的大小(先后)
public boolean equalTwoDates(DateUtil date);//判断两个日期是否相等
public int getDaysofDates(DateUtil date);//求当前日期与date之间相差的天数
public String showDate();//以“year-month-day”格式返回日期值
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
程序主方法如下:
import java.util.Scanner;
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);
}
}
}
输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):
- 1 year month day n //测试输入日期的下n天
- 2 year month day n //测试输入日期的前n天
- 3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
- 当输入有误时,输出格式如下:
Wrong Format - 当第一个数字为1且输入均有效,输出格式如下:
year1-month1-day1 next n days is:year2-month2-day2 - 当第一个数字为2且输入均有效,输出格式如下:
year1-month1-day1 previous n days is:year2-month2-day2 - 当第一个数字为3且输入均有效,输出格式如下:
The days between year1-month1-day1 and year2-month2-day2 are:值
输入样例1:
在这里给出一组输入。例如:
3 2014 2 14 2020 6 14
输出样例1:
在这里给出相应的输出。例如:
The days between 2014-2-14 and 2020-6-14 are:2312
输入样例2:
在这里给出一组输入。例如:
2 1834 2 17 7821
输出样例2:
在这里给出相应的输出。例如:
1834-2-17 previous 7821 days is:1812-9-19
输入样例3:
在这里给出一组输入。例如:
1 1999 3 28 6543
输出样例3:
在这里给出相应的输出。例如:
1999-3-28 next 6543 days is:2017-2-24
输入样例4:
在这里给出一组输入。例如:
0 2000 5 12 30
输出样例4:
在这里给出相应的输出。例如:
Wrong Format
1 import java.util.Scanner; 2 3 public class Main { 4 public static void main(String[] args) { 5 Scanner input = new Scanner(System.in); 6 int year = 0; 7 int month = 0; 8 int day = 0; 9 int choice = input.nextInt(); 10 if (choice == 1) { // test getNextNDays method 11 int m = 0; 12 year = Integer.parseInt(input.next()); 13 month = Integer.parseInt(input.next()); 14 day = Integer.parseInt(input.next()); 15 16 DateUtil date = new DateUtil(year, month, day); 17 18 if (!date.checkInputValidity()) { 19 System.out.println("Wrong Format"); 20 System.exit(0); 21 } 22 23 m = input.nextInt(); 24 25 if (m < 0) { 26 System.out.println("Wrong Format"); 27 System.exit(0); 28 } 29 30 System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:"); 31 System.out.println(date.getNextNDays(m).showDate()); 32 } else if (choice == 2) { // test getPreviousNDays method 33 int n = 0; 34 year = Integer.parseInt(input.next()); 35 month = Integer.parseInt(input.next()); 36 day = Integer.parseInt(input.next()); 37 38 DateUtil date = new DateUtil(year, month, day); 39 40 if (!date.checkInputValidity()) { 41 System.out.println("Wrong Format"); 42 System.exit(0); 43 } 44 45 n = input.nextInt(); 46 47 if (n < 0) { 48 System.out.println("Wrong Format"); 49 System.exit(0); 50 } 51 System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:"); 52 System.out.println(date.getPreviousNDays(n).showDate()); 53 } else if (choice == 3) { //test getDaysofDates method 54 year = Integer.parseInt(input.next()); 55 month = Integer.parseInt(input.next()); 56 day = Integer.parseInt(input.next()); 57 58 int anotherYear = Integer.parseInt(input.next()); 59 int anotherMonth = Integer.parseInt(input.next()); 60 int anotherDay = Integer.parseInt(input.next()); 61 62 DateUtil fromDate = new DateUtil(year, month, day); 63 DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay); 64 65 if (fromDate.checkInputValidity() && toDate.checkInputValidity()) { 66 System.out.println("The days between " + fromDate.showDate() + " and " + toDate.showDate() + " are:"+ fromDate.getDaysofDates(toDate)); 67 } else { 68 System.out.println("Wrong Format"); 69 System.exit(0); 70 } 71 } 72 else{ 73 System.out.println("Wrong Format"); 74 System.exit(0); 75 } 76 } 77 } 78 79 class DateUtil{ 80 private int year ;// 年份 81 private int month ;// 月份 82 private long day ;// 日数,因为要输入整型最大值,这里使用长整型防止计算过程中出错 83 public int YEAR ;// 用于判断年份是否合法 84 public int MONTH ;// 用于判断月份是否合法 85 public long DAY ;// 用于判断日数是否合法 86 protected int month_maxnum[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};// 各个月份的天数 87 88 public DateUtil(int Year,int Month,long Day){// 构造有参类,在此给年月日赋值 89 YEAR=Year; 90 MONTH=Month; 91 DAY=Day; 92 setyear(YEAR); 93 setmonth(MONTH); 94 setday(DAY); 95 } 96 97 public void setyear(int year){// 设置年份 98 this.year = year; 99 } 100 101 public void setmonth(int month){// 设置月份 102 this.month = month; 103 } 104 105 public void setday(long day){// 设置天数 106 this.day = day; 107 } 108 109 public int getYear(){// 得到年份 110 return this.year; 111 } 112 113 public int getMonth(){// 得到月份 114 return this.month; 115 } 116 117 public long getDay(){// 得到天数 118 return this.day; 119 } 120 121 public boolean checkInputValidity(){// 判断日期是否输入合法 122 if( YEAR>=1820 && YEAR<=2020 && MONTH>=1 && MONTH<=12 && DAY>=1 && DAY<=31 ){ 123 return true; 124 } 125 else 126 return false; 127 } 128 129 public boolean isLeapYear(int year){// 判断闰年 130 if( year % 4 == 0 ){ 131 if( year % 100 == 0 ){ 132 if( year % 400 == 0 ) return true; 133 else return false; 134 } 135 else return true; 136 } 137 else return false; 138 } 139 140 public DateUtil getNextNDays(long n){// 取得year-month-day的下n天日期 141 DateUtil DATE = new DateUtil(this.year,this.month,this.day); 142 if (MONTH == 1 || MONTH == 3 || MONTH == 5 || MONTH == 7 || MONTH == 8 || MONTH == 10 || MONTH == 12){ 143 if(this.day+n <= 31){// 后n天仍为该年该月 144 DATE.setday(DATE.getDay()+n); 145 } 146 else{ 147 DATE = modifydate(n); 148 } 149 } 150 else if (MONTH == 2){// 2月 151 if (this.day + n <= 29 && isLeapYear(year)){// 闰年,且后n天仍为该年2月 152 DATE.setday(DATE.getDay() + n); 153 } 154 else if (this.day+n <= 28 && !isLeapYear(year)){// 非闰年,且后n天仍为该年2月 155 DATE.setday(DATE.getDay() + n); 156 } 157 else{ 158 DATE = modifydate(n);// 后n天不再是该年的2月 159 } 160 } 161 else if (MONTH == 4 || MONTH == 6 || MONTH == 9 || MONTH == 11){ 162 if (this.day + n <= 30){// 后n天仍为该年该月 163 DATE.setday(DATE.getDay()+n); 164 } 165 else{ 166 DATE = modifydate(n); 167 } 168 } 169 return DATE; 170 } 171 172 public DateUtil getPreviousNDays(int n){// 取得year-month-day的前n天日期 173 DateUtil DATE = new DateUtil(this.year,this.month,this.day); 174 if(MONTH == 1 || MONTH == 3 || MONTH == 5 || MONTH == 7 || MONTH == 8 || MONTH == 10 || MONTH == 12){ 175 if( this.day>n ){// n小于目前的日 176 DATE.setday(DATE.getDay()-n);// 直接计算 177 } 178 else{ 179 DATE=modifydate2(n);// 调用计算前n天的函数 180 } 181 } 182 else if (MONTH == 2){// 2月 183 if (this.day > n){ 184 DATE.setday(DATE.getDay()-n); 185 } 186 else{ 187 DATE = modifydate2(n); 188 } 189 } 190 else if (MONTH == 4 || MONTH == 6 || MONTH == 9 || MONTH == 11){ 191 if (this.day > n){ 192 DATE.setday(DATE.getDay()-n); 193 } 194 else{ 195 DATE=modifydate2(n); 196 } 197 } 198 return DATE; 199 } 200 201 public boolean compareDates(DateUtil date){//如果是第一个日期大,则输出true 202 if(this.year>date.getYear()) 203 return true; 204 else if(this.year<date.getYear()) 205 return false; 206 else{ 207 if(this.month>date.getMonth()) 208 return true; 209 else if(this.month<date.getMonth()) 210 return false; 211 else{ 212 if(this.day>date.getDay()) 213 return true; 214 else if(this.day<date.getDay()) 215 return false; 216 else 217 return false;//相等 218 } 219 } 220 } 221 222 public boolean equalTwoDates(DateUtil date){// 比较两个天数是否相等 223 if( date.getYear()==this.year&&date.getMonth()==this.month&&date.getDay()==this.day ) 224 return true; 225 else 226 return false; 227 } 228 229 public int getDaysofDates(DateUtil date){// 求两天天数之差 230 int sum = 0; 231 int small_year=0,big_year=0; 232 int small_month=0,big_month=0; 233 int small_day=0,big_day=0; 234 int i1=0,i2=0,i3=0; 235 int month_condition=0,day_condition=0; 236 if (equalTwoDates(date))// 天数相等,直接返回0 237 return 0; 238 else{ 239 if (compareDates(date)){// 第一个日期大 240 small_year = date.getYear(); big_year = this.year; 241 small_month = date.getMonth(); big_month = this.month; 242 small_day = (int)date.getDay(); big_day = (int)this.day; 243 } 244 else{// 第二个日期大 245 big_year = date.getYear(); small_year = this.year; 246 big_month = date.getMonth(); small_month = this.month; 247 big_day = (int)date.getDay(); small_day = (int)this.day; 248 } 249 for( i1=small_year ; i1<=big_year ; i1++ ){// 从小年份一直循环到大年份 250 if (i1 == small_year){// 是否为输入小年份,如果是,则让i2等于输入的月份 251 i2 = small_month;// 让i2等于输入的月份 252 } 253 else{ 254 i2 = 1;// i1不是输入的小年份,让i2从一月开始 255 } 256 if (i1 == big_year){// 判断i1是否是大年份 257 month_condition = big_month;// 是,则i2循环到i2为大年份的月份 258 } 259 else{ 260 month_condition = 12;// 不是,一直让i2循环到i1这一年的12月 261 } 262 for (; i2<=month_condition; i2++){// i2月份循环 263 if(i1 == small_year && i2 == small_month )// 判断i1和i2是否都为输入的小日期的年份和月份 264 i3 = small_day;// 是,让i3日数等于输入的小日期的日数 265 else 266 i3 = 1;// 不是,从i2这个月第一天算起 267 if (i1 == big_year && i2 == big_month)// 判断i1和i2是否都为输入的大日期的年份和月份 268 day_condition = big_day;// 是,让i3一直循环到大日期的日数 269 else{ 270 if (isLeapYear(i1))// 判断是否为闰年,如果是闰年,则修正2月的天数 271 month_maxnum[2]=29;// 修正 272 else 273 month_maxnum[2]=28;// 不是则修正为28天 274 day_condition = month_maxnum[i2];// 判断i1和i2是否不都为输入的大日期的年份和月份,让i3一直循环到i2月份的最后一天 275 } 276 for(; i3 <= day_condition; i3++){ 277 sum++;// 天数之差+1,因为在最后一次循环中会多循环一次 278 } 279 } 280 } 281 } 282 return sum-1;// sum是相差天数+1.需要减1修正 283 } 284 285 public String showDate(){// 输出日期 286 return this.year+"-"+this.month+"-"+this.day; 287 } 288 289 public DateUtil modifydate(long n){// 求后n天 290 DateUtil DATE = new DateUtil(this.year,this.month,this.day); 291 int surplus_month = 0;// 后多少个月 292 DATE.setday(DATE.getDay()+n);// 先加上原来的日数 293 while(DATE.getDay() > 366){// 总的天数大于1一年的最大天数就继续循环 294 if (isLeapYear(DATE.getYear())){// 该年是闰年 295 DATE.setday(DATE.getDay()-366);// 减去闰年的总天数 296 DATE.setyear(DATE.getYear()+1);// 加上一年 297 } 298 else{ 299 DATE.setday(DATE.getDay()-365);// 减去非闰年的总天数 300 DATE.setyear(DATE.getYear()+1);// 加上一年 301 } 302 } 303 for( int i=MONTH ; ; i++ ){//计算n天后的日期和多出的月份 304 if( i>12 ){// 说明进入下一年了 305 i-=12;// 修正月份 306 DATE.setyear(DATE.getYear()+1);// 加上一年 307 } 308 if(i == 2 && isLeapYear(DATE.getYear()))// 若是闰年则修正月份天数 309 month_maxnum[2]=29; 310 else 311 month_maxnum[2]=28; 312 if(DATE.getDay() > month_maxnum[i])// 说明下n天还是大于该月的最大天数 313 DATE.setday(DATE.getDay() - month_maxnum[i]);// 修正天数 314 else 315 break; 316 surplus_month++;// 后多少个月+1 317 } 318 DATE.setmonth((DATE.getMonth()+surplus_month)%12);// 修正月份 319 return DATE; 320 } 321 322 public DateUtil modifydate2(long n){// 求前n天 323 DateUtil DATE = new DateUtil(this.year,this.month,this.day); 324 int surplus_month = 0;// 前多少个月 325 DATE.setday(n-DATE.getDay());// 前多少天,这里先做一次处理 326 while( DATE.getDay()>366 ){// 总的天数大于1年的最大天数就继续进行 327 if( isLeapYear(DATE.getYear()-1) ){// 判断前一年是不是闰年 328 DATE.setday(DATE.getDay()-366);// 是闰年就减366天 329 DATE.setyear(DATE.getYear()-1);// 年数也减一年 330 } 331 else{ 332 DATE.setday(DATE.getDay()-365);// 非闰年减去365天 333 DATE.setyear(DATE.getYear()-1);// 年数减一年 334 } 335 } 336 for(int i = MONTH; ;i--){ 337 if (i == 0){// 说明已经往前了一年 338 i=12;// 修正月份 339 DATE.setyear(DATE.getYear()-1);// 修正年份 340 } 341 if (i == 3 && isLeapYear(DATE.getYear())){// 闰年情况到了3月要给2月天数赋值,因为目前的前n天可能会让日期到达2月 342 month_maxnum[2]=29; 343 } 344 else {// 不是闰年则2月就一直28天 345 month_maxnum[2]=28; 346 } 347 if (DATE.getDay() > month_maxnum[i-1] && i-1 != 0)// 非1月的情况n依旧大于上个月最大天数 348 DATE.setday(DATE.getDay()-month_maxnum[i-1]);// 减上个月的天数 349 else if (DATE.getDay() > month_maxnum[12] && i-1 == 0)// 1月的情况n依旧大于上个月最大天数 350 DATE.setday(DATE.getDay()-month_maxnum[12]);// 减去12月的天数 351 else{// 说明n已经小于上个月的天数 352 if(i == 1) 353 DATE.setday(month_maxnum[12] - DATE.getDay());// 反过来减 354 else 355 DATE.setday(month_maxnum[i-1] - DATE.getDay()); 356 surplus_month--;// 前多少个月+1(负多少就是前多少个月) 357 break; 358 } 359 surplus_month--;// 前多少个月+1(负多少就是前多少个月) 360 } 361 if(DATE.getYear()<0) 362 DATE.setday(DATE.getDay()+1); 363 if(DATE.getMonth()+(surplus_month%12)<0) 364 DATE.setmonth(12+DATE.getMonth()+(surplus_month%12));//负数情况,说明月份需要从上年末月开始减 365 else 366 DATE.setmonth(DATE.getMonth()+(surplus_month%12));// 一般情况修正月份 367 return DATE; 368 } 369 }
SourceMonitor分析结果:

小结:从SourceMonitor的分析结果可以得知该题的代码十分复杂,且构造的方法和类非常多,这题难度很大。在解本题时,我采用的是一个一个功能地做,先从下n天做起,因为在之前的题目中已经遇到过求后一天的情况,相对来说后
n天会较为容易一点,但是在设计算法的过程中,发现相比想象中的要复杂很多。首先是因为n可以大于一个月的总天数,也可以大于一年的总天数,每个月份的天数都不一定相同,年份也分闰年和非闰年,在设计算法的时候试了
多错,花了很久才得以解决。做完后n天后便着手设计前n天的算法,最初的想法是直接代入-n到求下n天的方法中,但是由于我的算法并不通用于负数的情况,便又设计了另外的求前n天的算法,鉴于求下n天的经验,求前n天较为
轻松,但不知是算法还存在一定问题还是pta测试节点的问题,前n天的整型最大值测试节点无法正常通过,在给天数加上1后便可通过PTA,我有和别人一起输入同样的数据来比对输出结果,结果是完全一致,不太明白PTA的一些
判断机制,还请各路大神指教。最后便是求解两个日期之差的问题了,这个算法比较难,虽然一开始想反复调用求下n天或求前n天的方法来求两日期之差,但资源消耗太大,完全就是垃圾代码,便放弃了这个想法。之后思考一段
时间仍无果后便稍微借鉴了下别人的代码,得以解决该问题。总的来说,该题的难度还是很大的,需要花费很多时间去解,而不是一蹴而成的。
三、采坑心得
此处只讲进行设计与分析了的题目
OOP训练集01:
1、由于不太清楚Java,在选择编译器的时候,选择了JavaScript (node),导致一直编译错误和非零返回;

2、在做题前没有好好看题目说明,在编写主类的时候没有按照要求命名为Main而是一直随心所欲的命名,在多次提示编译错误后才注意到;

3、由于习惯了C语言float类型和double类型的常量是可以相互进行赋值运算的,于是在Java的题目中使用类似于 float a = 2; double b = 2 * a; 的运算报错,在查看编译器的报错提示后将 double b = 2 * a改为
double b = (double)2 * a 才得以解决问题;

4、总是不注意输出格式,例如在7-1题中需要保留两位小数输出,而一直没注意到,还有在7-3题中由于没注意格式,将两个乘数的位置搞反;

5、总是漏掉分号;,之后便更加注意敲完每一条语句后是否又加上分号 ;

6、误认为Java中的数组定义语句与C语言一样,都是直接 xx类型 s[n],导致编译报错,后查阅资料得知应该按照 xx类型 数组名字 = new xx类型[n] 的格式来进行定义数组;

7、习惯了C语言的规则,认为字符串可以正常使用charAt()返回空字符来作为是否终止循环的条件,导致非零返回,例如for(int i=0;s.charAt(i)!='\0';i++),同时也误认为可以像C语言一样直接对String类型的
数据进行修改,实则不然,应该使用StringBuilder类型的数据;


OOP训练集02:
1、在7-8判断三角形中,对直角三角形的判断直接使用 a²+b²=c² 的形式进行判断,忘记计算机是无法计算绝对精确的数值的,导致判断等腰直角三角形这个节点一直无法通过,后将其改为了a²+b²-c²的绝对值
小于一个很小的数值便认为该三角形为直角三角形便通过了测试点,对计算机数值的了解得到了更进一步的认识;

2、在7-9求下一天中,构造方法中,构造了非无类型的方法,使用if...else语句没有补全所有情况应该都有返回值,导致编译一直提示错误,现设计非无类型方法时会更加注意if...else语句的使用

OOP训练集03:
1、刚开始并不知道该如何将参数传入主类外的类的变量中,后查阅资料得知该道题构造的是无参类,应该用该类中的方法对其进行赋值,在7-1题中

2、在7-4题中,计算前n天和下n天,如果n比好几年加起来的天数还要大,不应该是直接使用n%365或者n%366,因为闰年和非闰年都是存在的,在刚开始时并没有注意到,导致一直计算出错;

四、改进建议
1、对于OOP训练集02中的7-8题,我认为在普通直角三形的判断那还需要改进一下,而不是单单的a²+b²=c²,应该和判断等腰直角三角形一样让a²+b²-c²的绝对值小于一个很小的值;

2、对于OOP训练集02中的7-9题,我认为代码可以再少一点if语句,并且用数组将每个月月份所对应的最大天数存储起来,使它们看起来更有联系,而不是单单地在判断语句中用一个常数判断;

3、对于OOP训练集03中的7-4题,我认为算法还可以再改进一下,因为我的算法在一些测试节点中存在一些问题,虽然自测没问题,但也是个仍需改进的原因,而且代码冗长,在提交的时候也出现过多次代
码长度超出限制的警告;


五、总结
1、通过三次作业,让我对Java的语法有了一个基本的认知,也让我掌握了些许Java语法,可以设计一些简单的Java编程;
2、通过这三次作业,让我体会到了Java与C语言的一些不同之处,有很多地方Java与C是不共通的,就例如数组的定义。同时,也发现了Java在很多方面都要比C更好,Java提供的类和方法大多数情况下都要比C好用的多;
3、这三次作业让我了解到了OOP并不是一门简单的课程,而是需要花费大量精力才能去把它学会、学好的,对待作业,丝毫不能怠慢;
4、在进行程序设计的时候,敲代码前时闹钟应该有一个基本的框架,而不是看完题目就动手敲,这样才能大大降低出错率;
5、在算法逻辑与Java语法的学习之路,依旧很远,需要不断地去学习;
6、对于教师、课程、作业、实验、课上及课下组织方式等方面,目前认为大体挺好,学习压力确实较大,但是也并没有让人完全适应不了,虽然有时候确实想题目少一点,简单一点,但是总的来说多一点、少一点,也能有效促进学生
在OOP方面能力的提升。

浙公网安备 33010602011771号