Boke-liu的BLOG-1
一、前言
最近这段时间在PTA做了Java的三次题目集,先做个总结:
①第一次题目集是对教材前八章自学内容的考核,通过前八章的学习了解了Java,还学习了像基本数据类型、变量、常量、赋值、表达式以及操作符这样的基本程序设计技术,选择语句,数学函数、字符和字符串,循环,方法,数组。这次题目集有九题,题量一点点多吧,但我们学习过C语言又只是前八章的语法,所以难度不算大。题目包括身高质量指数(BMI)测算、长度质量计量单位换算、奇数求和、房产税费计算、游戏角色选择、学号识别、巴比伦法求平方根近似值、二进制数值提取、判断三角形类型。
②第二次题目集考察了字符串的有关内容,知识点主要有获取字符串长度、比较两个字符串是否相等、字符串的查找和截取字符串、字符串转换为字符数组。题目集中有三题,题目包括字母-数字的转换、串口字符解析、String的格式判断与内容提取,虽然只有三题,但是这三题稍微有一点点难度,当把这三题做到全对之后还是挺有成就感的。
③第三次题目集考察了面向对象程序设计的类与对象,题目集中有四题,包括用类解一元二次方程式、日期类设计、日期问题面向对象设计(聚合一)、日期问题面向对象设计(聚合二),从这次题目集开始就有难度了,做题目所花的时间也更多了,这两个聚合的题目给出了相应的类图,我们需要根据类图来写我们的程序。
二、设计与分析
①题目集01的7-1主要运用的是if-else语句,题目要求如下:
输入格式:
两个数值:体重(以千克为单位),身高(以米为单位),数值间以空格分隔。例如: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”。
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); double high,weight,bmi; weight=in.nextDouble(); high=in.nextDouble(); if(high>2.72||high<=0) { System.out.println("input out of range"); } else if(weight>727||weight<=0) { System.out.println("input out of range"); } else { bmi=weight/(high*high); if(bmi<18.5) { System.out.println("thin"); } else if(bmi>=18.5&&bmi<24.05) { System.out.println("fit"); } else if(bmi>=24.05&&bmi<28.05) { System.out.println("overweight"); } else if(bmi>=28) { System.out.println("fat"); } } } }
运用if-else语句对不同情况进行分类,从而实现不同情况的讨论与输出。
②题目集01的7-2主要考查数据类型,题目要求如下:
长度、质量的计量有多重不同的计算体系,有标准的国际单位制:千克与米,也有各个国家自己的计量方法如:磅、英寸;1磅等于0.45359237千克,1英寸等于0.0254米,请编写程序实现国际单位制与英制之间的换算。
输入格式:
两个浮点数,以空格分隔,第一个是质量(以千克为单位)、第二个是长度(以米为单位)。例如:0.45359237 0.0254。
输出格式:
两个浮点数,以空格分隔,第一个是质量(以磅为单位)、第二个是长度(以英寸为单位)。例如:1.0 1.0。
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); float w,l; w=in.nextFloat(); l=in.nextFloat(); w=(float)(w/0.45359237); l=(float)(l/0.0254); System.out.print(w+" "+l); } }
运用float的数据类型表示单位换算前后的数据,通过这个题目我知道了要找准题目需要我们运用的数据类型,才能达到题目要求的数据精度。
③题目集01的7-3主要运用的是循环语句,题目要求如下:
计算一个数列中所有奇数的和。
输入格式:
十个整数,以空格分隔。例如:1 2 3 4 5 6 7 8 9 0。
输出格式:
输入数列中所有奇数之和。例如:25。
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int []a=new int[10]; int sum=0; for(int i=0;i<10;i++) { a[i]=in.nextInt(); } for(int i=0;i<10;i++) { if(a[i]%2==1||a[i]%2==-1) { sum=sum+a[i]; } } System.out.println(sum); } }
运用循环实现输入多个数据,运用循环求多个数的和,同时在循环里给出求和的条件,即如果是奇数才求和,最后输出结果。
④题目集01的7-4主要考查的是数据类型的强制转换,题目要求如下:
房屋交易在日常生活中非常常见的事情,房屋交易时要额外支付各种税费,按2022年房产交易新政策的规定买房人应缴纳税费包括:
1、契税:首次购房评估额90平(含)内1%、90平-144平(含)内1.5%,超过144平或非首 次3%,买方缴纳。
2、印花税:房款的0.05%。
3、交易费:3元/平方米。
4、测绘费:1.36元/平方米。
5、权属登记费及取证费:一般情况是在200元内。
输入格式:
四个数据,以空格分隔:
1、第几次购房(整数)
2、房款(整数/单位万元)
3、评估价(整数/单位万元)
4、房屋面积(浮点数/单位平方米)。
例如:1 100 100 90。
输出格式:
契税、印花税、交易费、测绘费(以元为单位),以空格分隔。例如:10000.0 500.0 270.0 122.4
import java.util.Scanner; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); int a,b,c; float d,e=1,f,m,n; a=in.nextInt(); b=in.nextInt(); c=in.nextInt(); d=in.nextFloat(); if(a==1) { if(d<=90) e=(float)(c*0.01*10000); else if(d>90&&d<=144) e=(float)(c*0.015*10000); else if(d>144) e=(float)(c*0.03*10000); } else e=(float)(c*0.03*10000); f=(float)(b*0.0005*10000); m=(float)(d*3); n=(float)(d*1.36); System.out.println(e+" "+f+" "+m+" "+n); } }
计算之后数据的类型要正确,而使用强制转换。
⑤题目集01的7-5主要考查的是if-elsse条件判断里又进行条件判断,题目要求如下:
一款网游中包括4个种族:人类、精灵、兽人、暗精灵,每个种族包含三种角色:战士、法师、射手。玩家新建人物时需要选择种族和角色。请编写角色选择程序。
输入格式:
两个整数:游戏种族、角色的选项,以空格分隔。例如:1 2。
种族选项设定为:1、人类 2、精灵 3、兽人 4、暗精灵
角色选项设定为:1、战士 2、法师 3、射手
输出格式:
所选择的种族、角色的名称,以空格分隔。例如:人类 法师
若输入数值超出选项范围,输出“Wrong Format”
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int a,b; a=in.nextInt(); b=in.nextInt(); if(a==1) { if(b==1) System.out.println("人类"+" "+"战士"); else if(b==2) System.out.println("人类"+" "+"法师"); else if(b==3) System.out.println("人类"+" "+"射手"); else System.out.println("Wrong Format"); } else if(a==2) { if(b==1) System.out.println("精灵"+" "+"战士"); else if(b==2) System.out.println("精灵"+" "+"法师"); else if(b==3) System.out.println("精灵"+" "+"射手"); else System.out.println("Wrong Format"); } else if(a==3) { if(b==1) System.out.println("兽人"+" "+"战士"); else if(b==2) System.out.println("兽人"+" "+"法师"); else if(b==3) System.out.println("兽人"+" "+"射手"); else System.out.println("Wrong Format"); } else if(a==4) { if(b==1) System.out.println("暗精灵"+" "+"战士"); else if(b==2) System.out.println("暗精灵"+" "+"法师"); else if(b==3) System.out.println("暗精灵"+" "+"射手"); else System.out.println("Wrong Format"); } else System.out.println("Wrong Format"); } }
先从大情况进行条件判断,进行大分类,再进行每一情况里的分类,从而实现多重分类。
⑥题目集01的7-6主要运用字符串的相关内容,题目要求如下:
学校的学号由8位数字组成,前两位是入学年份(省略了20);第3、4位是学院编号,01代表材料学院,02代表机械学院,03代表外语学院,20代表软件学院;第5、6位是学院内部班级编号,最后两位是班级内部学号。如:18011103,入学年份是2018年,材料学院,11班,03号
输入格式:
8位数字组成的学号。例如:18011103
注意:输入学号不是8位或者学院编号不是01、02、03、20其中之一,属于非法输入
输出格式:
学号每一项的完整说明。例如:
入学年份:2018年
学院:材料学院
班级:11
学号:03
注意:如非法输入,输出“Wrong Format"
import java.util.Scanner; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); String str=in.nextLine(); String a="01"; String b="02"; String c="03"; String d="20"; if(str.length()!=8) System.out.println("Wrong Format"); else if(str.substring(2,4).equals(a)) { System.out.println("入学年份:20"+str.substring(0,2)+"年"); System.out.println("学院:材料学院"); System.out.println("班级:"+str.substring(4,6)); System.out.println("学号:"+str.substring(6,8)); } else if(str.substring(2,4).equals(b)) { System.out.println("入学年份:20"+str.substring(0,2)+"年"); System.out.println("学院:机械学院"); System.out.println("班级:"+str.substring(4,6)); System.out.println("学号:"+str.substring(6,8)); } else if(str.substring(2,4).equals(c)) { System.out.println("入学年份:20"+str.substring(0,2)+"年"); System.out.println("学院:外语学院"); System.out.println("班级:"+str.substring(4,6)); System.out.println("学号:"+str.substring(6,8)); } else if(str.substring(2,4).equals(d)) { System.out.println("入学年份:20"+str.substring(0,2)+"年"); System.out.println("学院:软件学院"); System.out.println("班级:"+str.substring(4,6)); System.out.println("学号:"+str.substring(6,8)); } else { System.out.println("Wrong Format"); } } }
我做这题的时候运用了字符串的相关内容:获取字符串的长度、截取字符串和字符串的比较,先判断符合条件的字符串,再从给出的一个字符串截取它决定学院的部分与代表每个学院的字符串进行比较,然后进行分类,再截取字符串里给出的对应信息,最后根据要求输出相关性息。
⑦题目集01的7-8主要考查数据类型的选用与if-else的条件判断,还需要运用循环进行相关计算,题目要求如下:
巴比伦法求n的近似值可以用以下公式:
nextGuess = (lastGuess+n/lastGuess)/2
程序初始运行时lastGuess可赋予一个最初的猜测值。当由公式求得的nextGuess和lastGuess相差较大时,把nextGuess的值赋给lastGuess,继续以上过程,直至nextGuess和lastGuess几乎相同,此时lastGuess或者nextGuess就是平方根的近似值。
本题要求:nextGuess和lastGuess的差值小于0.00001时认为两者几乎相同
输入格式:
1、两个浮点数,以空格分隔,第一个是n,第二个是lastGuess最初的猜测值。例如:2 1。
2、若输入的两个数中包含负数或者lastGuess初始输入为0,认定为非法输入
输出格式:
1、输出n的平方根近似值:lastGuess。例如:1.4142157
2、非法输入时输出:"Wrong Format"
import java.util.Scanner; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); float n; float m; float nextGuess; n=in.nextFloat(); m=in.nextFloat(); if(n<0) System.out.println("Wrong Format"); else if(m<=0) System.out.println("Wrong Format"); else { nextGuess=(m+n/m)/2; for(;m-nextGuess>=0.00001||nextGuess-m>=0.00001;) { m=nextGuess; nextGuess=(m+n/m)/2; } System.out.print(m); } } }
先对输入的两个数据进行判断是否符合要求,然后对符合要讲的数据先进行一次运算再按照题目要求进行循环计算。
⑧题目集01的7-9也考查字符串的相关内容,题目要求如下:
在一个字符串中提取出其中的二进制数值序列,。
输入格式:
一个由0、1构成的序列,以-1为结束符,非0、1字符视为正常输入,但忽略不计,未包含结束符的序列视为非法输入。例如:abc00aj014421-1
输出格式:
将输入的序列去掉非0、1字符以及结尾符的数据内容,
注:结束符-1之后的0\1字符忽略不计。
例如:00011。
import java.util.Scanner; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); String str=in.nextLine(); char []a=str.toCharArray(); if(str.indexOf("-1")==-1) { System.out.println("Wrong Format"); } else { String b=str.substring(0,str.indexOf("-1")); for(int i=0;i<b.length();i++) { if(a[i]==48||a[i]==49) { System.out.print(a[i]); } } } } }
先查找输入的字符串中是否含有-1,有就截取字符串中-1以前的部分,再将字符串中的元素进行逐一判断,是0或1就输出。
⑨题目集01的7-7主要考查的是多情况的判断与数据的偏差,题目要求如下:
输入三角形三条边,判断该三角形为什么类型的三角形。
输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[1,200]。
输出格式:
(1)如果输入数据非法,则输出“Wrong Format”;
(2)如果输入数据合法,但三条边不能构成三角形,则输出“Not a triangle”;
(3)如果输入数据合法且能够成等边三角形,则输出“Equilateral triangle”;
(4)如果输入数据合法且能够成等腰直角三角形,则输出“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) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); double a,b,c,d; a=in.nextDouble(); b=in.nextDouble(); c=in.nextDouble(); d=0.000001; if(a>=1&&a<=200&&b>=1&&b<=200&&c>=1&&c<=200) { if(a+b>c&&b+c>a&&a+c>b) { if(a==b&&b==c) System.out.println("Equilateral triangle"); else if(a==b||a==c||b==c) { if(a*a+b*b<c*c+d&&a*a+b*b>c*c-d||a*a+c*c>b*b-d&&a*a+c*c<b*b+d||b*b+c*c>a*a-d&&b*b+c*c<a*a+d) System.out.println("Isosceles right-angled triangle"); else System.out.println("Isosceles triangle"); } else if(a*a+b*b<c*c+d&&a*a+b*b>c*c-d||a*a+c*c>b*b-d&&a*a+c*c<b*b+d||b*b+c*c>a*a-d&&b*b+c*c<a*a+d) System.out.println("Right-angled triangle"); else System.out.println("General triangle"); } else System.out.println("Not a triangle"); } else System.out.println("Wrong Format"); } }
⑩题目集02的7-2也是考查字符串的相关内容,题目要求如下:
RS232是串口常用的通信协议,在异步通信模式下,串口可以一次发送5~8位数据,收发双方之间没有数据发送时线路维持高电平,相当于接收方持续收到数据“1”(称为空闲位),发送方有数据发送时,会在有效数据(5~8位,具体位数由通信双方提前设置)前加上1位起始位“0”,在有效数据之后加上1位可选的奇偶校验位和1位结束位“1”。请编写程序,模拟串口接收处理程序,注:假定有效数据是8位,奇偶校验位采用奇校验。
输入格式:
由0、1组成的二进制数据流。例如:11110111010111111001001101111111011111111101111
输出格式:
过滤掉空闲、起始、结束以及奇偶校验位之后的数据,数据之前加上序号和英文冒号。
如有多个数据,每个数据单独一行显示。
若数据不足11位或者输入数据全1没有起始位,则输出"null data",
若某个数据的结束符不为1,则输出“validate error”。
若某个数据奇偶校验错误,则输出“parity check error”。
若数据结束符和奇偶校验均不合格,输出“validate error”。
如:11011或11111111111111111。
例如:
1:11101011
2:01001101
3:validate error
import java.util.Scanner; public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); String str=in.nextLine(); if(str.length()<11) { System.out.println("null data"); } else if(str.indexOf("0")==-1) { System.out.println("null data"); } else { int m,sum; for(int i=0;str.indexOf("0")!=-1;i++) { char []a=str.toCharArray(); m=str.indexOf("0"); String b=str.substring(m+1,m+9); char []c=b.toCharArray(); sum=c[0]+c[1]+c[2]+c[3]+c[4]+c[5]+c[6]+c[7]+a[m+9]-48*9; if(sum%2==1&&a[m+10]==49) { System.out.println(i+1+":"+b); } else if(sum%2==1&&a[m+10]!=49) System.out.println(i+1+":"+"validate error"); else if(sum%2!=1&&a[m+10]==49) System.out.println(i+1+":"+"parity check error"); else System.out.println(i+1+":"+"validate error"); str=str.substring(m+11); } } } }
首先判断字符串是否符合要求,判断字符串的长度是否大于11,判断字符串中是否含有0,对符合要求的字符串进行查找0所在的位置,在截取0后一到九位数字求和判断奇偶效应,再判断数据结束符是否符合要求,分情况进行讨论输出,再截取数据结束符后的字符串循环执行上述步骤。做题目时应理清思路再编写程序,可以通过调试找到逻辑上的错误。
第十一、题目集03的7-1用类解一元二次方程,题目要求如下:
定义一个代表一元二次方程ax2+bx+c=0的类QuadraticEquation,其属性为三个系数a、b、c(均为私有属性),类中定义的方法参考main方法中的代码
输入格式:
在一行中输入a、b、c的值,可以用一个或多个空格或回车符分开。
输出格式:
- 当输入非法时,输出“Wrong Format”
- 当有一个实根时,输出(2行):
- a=值,b=值,c=值:
- The root is 值(保留两位小数)
- 当有两个实根时,输出(2行):
- a=值,b=值,c=值:
- The roots are 值1 and 值2(均保留两位小数)
import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner input = new Scanner(System.in); double a = Double.parseDouble(input.next()); double b = Double.parseDouble(input.next()); double c = Double.parseDouble(input.next()); if(a == 0){ System.out.println("Wrong Format"); System.exit(0); } //create a QuadraticEquation object QuadraticEquation equation = new QuadraticEquation(a, b, c); //get value of b * b - 4 * a * c double discriminant = equation.getDiscriminant(); System.out.println("a=" + equation.getA() + ",b=" + equation.getB() + ",c=" + equation.getC()+":"); if (discriminant < 0) { System.out.println("The equation has no roots."); } else if (discriminant == 0) { System.out.println("The root is " + String.format("%.2f", equation.getRoot1())); } else // (discriminant >= 0) { System.out.println("The roots are " + String.format("%.2f", equation.getRoot1()) + " and " + String.format("%.2f", equation.getRoot2())); } } } class QuadraticEquation{ //your code private double a; private double b; private double c; public QuadraticEquation() { } public QuadraticEquation(double a,double b,double c) { this.a = a; this.b = b; this.c = c; } public double getDiscriminant() { return b * b - 4 * a * c; } public double getA() { return this.a; } public double getB() { return this.b; } public double getC() { return this.c; } public double getRoot1() { return (-b+Math.sqrt(b * b - 4 * a * c))/2*a; } public double getRoot2() { return (-b-Math.sqrt(b * b - 4 * a * c))/2*a; } }
用类计算一元二次方程的两个根,在主方法里创建一对象,从而调用这个类的方法。类里需要三个私有属性a,b,c,分别为一元二次方程的系数和常数项,通过double类型的两个方法返回方程的两个跟。
第十二、题目集02的7-2设计一个日期类,题目要求如下:
参考题目集二中和日期相关的程序,设计一个类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天
- 求两个日期相差的天数
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); } } } class DateUtil{ private int year; private int month; private int day; public DateUtil() { } public DateUtil(int year,int month,int day) { this.year = year; this.month = month; this.day = day; } public void setYear() { this.year = year; } public int getYear() { return this.year; } public void setMonth() { this.month = month; } public int getMonth() { return this.month; } public void setDay() { this.day = day; } public int getDay() { return this.day; } public boolean checkInputValidity(){ //检测输入的年、月、日是否合法 int[] aa=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31}; if(isLeapYear(year)) aa[2] = 29; if(year>=1820&&year<=2020){ if(month>=1&&month<=12){ if(day>=1&&day<=aa[month]){ return true; } else{ return false; } } else{ return false; } } else{ return false; } } public boolean isLeapYear(int year){ //判断year是否为闰年 if ((year%4==0)&&(year%100!=0)||(year%400==0)){ return true; } else{ return false; } } int[] aa = new int[]{0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; private int getDayOfMonth(int year, int month) { int days = aa[month]; if (month == 2 && isLeapYear(year)) { days = 29; } return days; } public DateUtil getNextNDays(int n){ //取得year-month-day的下n天日期 int[] aa=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31}; int days = aa[month]; if(isLeapYear(year)) aa[2] = 29; int year = this.year; int month = this.month; int day = this.day; for (int i = 0; i < n; i++) { day++; if (day > getDayOfMonth(year, month)) { day = 1; month++; if (month > 12) { month = 1; year++; } } } return new DateUtil(year, month, day); } public DateUtil getPreviousNDays(int n){ //取得year-month-day的前n天日期 int year = this.year; int month = this.month; int day = this.day; for (int i = 0; i < n; i++) { day--; while (day < 1) { month--; if (month < 1) { month = 12; year--; } day += getDayOfMonth(year, month); } } return new DateUtil(year, month, day); } public boolean compareDates(DateUtil date){ //比较当前日期与date的大小(先后) if (this.year > date.year) return true; if (this.year == date.year) { if (this.month > date.month) return true; if (this.month == date.month) { if (this.day >= date.day) return true; } } return false; } 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){ //求当前日期与date之间相差的天数 int[] bb = new int[]{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; DateUtil dateUtil1 = this; DateUtil dateUtil2 = date; if (this.compareDates(date)) { dateUtil1 = date; dateUtil2 = this; } int days; int leapYearNum = 0; for (int i = dateUtil1.getYear(); i < dateUtil2.getYear(); i++) { if (isLeapYear(i)) { leapYearNum++; } } days = 365 * (dateUtil2.getYear() - dateUtil1.getYear()) + leapYearNum; int d1 = bb[dateUtil1.getMonth() - 1] + dateUtil1.getDay() + (dateUtil1.getMonth() > 2 && isLeapYear(dateUtil1.getYear()) ? 1 : 0); int d2 = bb[dateUtil2.getMonth() - 1] + dateUtil2.getDay() + (dateUtil2.getMonth() > 2 && isLeapYear(dateUtil2.getYear()) ? 1 : 0); return days - d1 + d2; } public String showDate(){ //以“year-month-day”格式返回日期值 return year+"-"+month+"-"+day; } }
类里检测输入的年月日是否合法时用一个数组记录每月的最大天数,当为闰年时将二月的28天改为29天,下面的方法里也要用到这个处理。
第十三、题目集03的7-3日期设计面向对象设计(聚合一),题目要求如下:
参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
import java.util.Scanner; class Year{ int value; public Year(){//默认构造方法 } public Year(int value){//带参构造方法 this.value=value; } public int getValue(){//value getter return value; } public void setValue(int value){//value setter this.value=value; } public boolean isLeapYear(){//判断year是否为闰年 if((value%4==0&&value%100!=0)||value%400==0) return true; else return false; } public boolean validate(){//效验数据合法性 if(value<=2050&&value>=1900) return true; else return false; } public void yearIncrement(){//年份加一 value=value+1; } public void yearReduction(){//年份减一 value=value-1; } } class Month{ int value; Year year; public Month(){//默认构造方法 } public Month(int yearValue,int monthValue){//带参构造方法 this.year=new Year(yearValue); this.value=monthValue; } public int getValue(){//value getter return value; } public Year getYear(){//year getter return year; } public void setValue(int value){//value setter this.value=value; } public void setYear(Year year){//year setter this.year=year; } public void resetMin(){//日期复位(1) value=1; } public void resetMax(){//月份设置为12 value=12; } public boolean validate(){//效验数据合法性 if(value>=1&&value<=12) return true; else return false; } public void monthIncrement(){//月份加一 value=value+1; } public void monthReduction(){//月份减一 value=value-1; } } class Day{ int value; Month month; int mon_maxnum[]={31,28,31,30,31,30,31,31,30,31,30,31}; public Day(){//默认构造方法 } public Day(int yearValue,int monthValue,int dayValue){//默认构造方法 this.month=new Month(yearValue,monthValue); this.value=dayValue; } public int getValue(){//value getter return value; } public void setValue(int value){//value setter this.value=value; } public Month getMonth(){//month getter return month; } public void setMonth(Month value){//month setter this.month=value; } public void resetMin(){//日期复位(1) value=1; } public void resetMax(){//日期设为该月最大值 value=mon_maxnum[month.getValue()-1]; } public boolean validate(){//效验数据合法性 if(this.getMonth().getYear().isLeapYear()) mon_maxnum[1]=29; if(value>=1&&value<=mon_maxnum[month.getValue()-1]) return true; else return false; } public void dayIncrement() {//日期加一 value=value+1; } public void dayReduction() {//日期减一 value=value-1; } } class DateUtil{ Day day; public DateUtil(){//默认构造方法 } public DateUtil(int d,int m,int y){//带参构造方法 this.day=new Day(d,m,y); } public Day getDay(){//day getter return day; } public void setDay(Day d){//day setter this.day=d; } public boolean checkInputValidity(){//效验数据合法性 if(this.getDay().getMonth().getYear().validate()&&this.getDay().getMonth().validate()&&day.validate()) return true; else return false; } public boolean compareDates(DateUtil date) {//比较两个日期的大小 if(date.getDay().getMonth().getYear().getValue()<this.getDay().getMonth().getYear().getValue()) return false; else if(date.getDay().getMonth().getYear().getValue()==this.getDay().getMonth().getYear().getValue()&&date.getDay().getMonth().getValue()<this.getDay().getMonth().getValue()) return false; else if(date.getDay().getMonth().getYear().getValue()==this.getDay().getMonth().getYear().getValue()&&date.getDay().getMonth().getValue()==this.getDay().getMonth().getValue()&&date.getDay().getValue()<this.getDay().getValue()) return false; else return true; } public boolean equalTwoDates(DateUtil date){//判定两个日期是否相等 if(this.getDay().getValue()==date.getDay().getValue()&&this.getDay().getMonth().getValue()==date.getDay().getMonth().getValue()&& this.getDay().getMonth().getYear().getValue()==date.getDay().getMonth().getYear().getValue()) return true; else return false; } public String showDate(){//日期值格式化 return this.getDay().getMonth().getYear().getValue()+"-"+this.getDay().getMonth().getValue()+"-"+this.getDay().getValue(); } int[] aa = new int[]{0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; private int getDayOfMonth(int year, int month) { int days = aa[month]; if (month == 2 && new Year(year).isLeapYear()) { days = 29; } return days; } public DateUtil getNextNDays(int n){//求下n天 int[] aa=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31}; int days = aa[this.getDay().getMonth().getValue()]; if(new Year(this.getDay().getMonth().getYear().getValue()).isLeapYear()) aa[2] = 29; int y = this.getDay().getMonth().getYear().getValue(); int m = this.getDay().getMonth().getValue(); int d = this.getDay().getValue(); for (int i = 0; i < n; i++) { d++; if (d > getDayOfMonth(y, m)) { d = 1; m++; if (m > 12) { m = 1; y++; } } } return new DateUtil(y, m, d); } public DateUtil getPreviousNDays(int n){//求前n天 int y = this.getDay().getMonth().getYear().getValue(); int m = this.getDay().getMonth().getValue(); int d = this.getDay().getValue(); for (int i = 0; i < n; i++) { d--; while (d < 1) { m--; if (m < 1) { m = 12; y--; } d += getDayOfMonth(y, m); } } return new DateUtil(y, m, d); } public int getDaysofDates(DateUtil date){//求两个日期之间的天数 DateUtil b1=this; DateUtil b2=date; if(this.equalTwoDates(date)){//如果两天的日期相等 return 0; } else if(!this.compareDates(date)){//如果日期大小不对 b1=date; b2=this; } int a[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int i,j,ts=0; for(i=b1.getDay().getMonth().getYear().getValue()+1;i<b2.getDay().getMonth().getYear().getValue();i++){//两个日期的年数之和 ts=ts+365; if(new Year(i).isLeapYear()) ts++; } if(b1.getDay().getMonth().getYear().getValue()==b2.getDay().getMonth().getYear().getValue()&&b1.getDay().getMonth().getValue()==b2.getDay().getMonth().getValue()){//年份相同,月份相同,日不同 ts=b2.getDay().getValue()-b1.getDay().getValue(); } else if(b1.getDay().getMonth().getYear().getValue()==b2.getDay().getMonth().getYear().getValue()&&b1.getDay().getMonth().getValue()!=b2.getDay().getMonth().getValue()){//年份相同,月份不同 if(b1.getDay().getMonth().getYear().isLeapYear())//是闰年 a[2]=29; ts=ts+a[b1.getDay().getMonth().getValue()]-b1.getDay().getValue();//小日期该月剩余的天数 ts=ts+b2.getDay().getValue();//大日期的天数 for(j=b1.getDay().getMonth().getValue()+1;j<=b2.getDay().getMonth().getValue()-1;j++)//月份天数和 ts+=a[j]; } else if(b1.getDay().getMonth().getYear().getValue()!=b2.getDay().getMonth().getYear().getValue()){//年份不同 ts=ts+a[b1.getDay().getMonth().getValue()]-b1.getDay().getValue();//小日期在该月剩余的天数 ts=ts+b2.getDay().getValue();//大日期在该月已经过的天数 for(j=b1.getDay().getMonth().getValue()+1;j<=12;j++)//小日期在该年剩余的天数 ts=ts+a[j]; for(j=b2.getDay().getMonth().getValue()-1;j>0;j--)//大日期在该年已经过的天数 ts=ts+a[j]; if(b1.getDay().getMonth().getYear().isLeapYear()&&b1.getDay().getMonth().getValue()<=2)//如果小日期该年为闰年且该天在1月或2月 ts++; if(b2.getDay().getMonth().getYear().isLeapYear()&&b2.getDay().getMonth().getValue()>2)//如果大日期该年为闰年且该天在1月或2月后 ts++; } return ts; } } 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.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.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(fromDate.getDaysofDates(toDate)); } else { System.out.println("Wrong Format"); System.exit(0); } } else{ System.out.println("Wrong Format"); System.exit(0); } } }
三个类之间的耦合性较大,三个类之间的关联较大,后一个类里用了前一个类的对象,应降低类之间的耦合性,是各个类只做自己的事情。
相比于7-3,7-4的耦合性更低
import java.util.Scanner; class Year{//Year类 int value; public Year(){ } public Year(int value){ this.value=value; } public int getValue(){ return value; } public void setValue(int value){ this.value=value; } public boolean isLeapYear(){ if((value%4==0&&value%100!=0)||value%400==0) return true; else return false; } public boolean validate(){ if(value<=2020&&value>=1820) return true; else return false; } public void yearIncrement(){ value=value+1; } public void yearReduction(){ value=value-1; } } class Month{//Month类 int value; public Month(){ } public Month(int value){ this.value=value; } public int getValue(){ return value; } public void setValue(int value){ this.value=value; } public void resetMin(){ value=1; } public void resetMax(){ value=12; } public boolean validate(){ if(value>=1&&value<=12) return true; else return false; } public void dayIncrement(){ value=value+1; } public void dayReduction(){ value=value-1; } } class Day{//Day类 int value; public Day(){ } public Day(int value){ this.value=value; } public int getValue(){ return value; } public void setValue(int value){ this.value=value; } public void dayIncrement() { value=value+1; } public void dayReduction() { value=value-1; } } class DateUtil{//DateUtil类 Year year; Month month; Day day; int mon_maxnum[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; public DateUtil(){ } public DateUtil(int y,int m,int d){ this.year = new Year(y); this.month = new Month(m); this.day = new Day(d); } public Year getYear(){ return year; } public Month getMonth(){ return month; } public Day getDay(){ return day; } public void setYear(Year year){ this.year = year; } public void setMonth(Month month){ this.month = month; } public void setDay(Day d){ this.day=d; } public void setDayMin() { this.day.value=1; } public void setDatMax() { if(this.year.isLeapYear()) mon_maxnum[2]=29; this.day.value=mon_maxnum[this.month.value]; } public boolean checkInputValidity(){ if(this.year.isLeapYear()) mon_maxnum[2]=29; if(this.year.validate()&&this.month.validate()&&this.day.value>=1&&this.day.value<=mon_maxnum[this.month.value]) return true; else return false; } int[] aa = new int[]{0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; private int getDayOfMonth(int y, int m) { int days = aa[m]; if (m == 2 && new Year(y).isLeapYear()) { days = 29; } return days; } public DateUtil getNextNDays(int n){ int[] aa=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31}; int days = aa[this.month.value]; if(new Year(this.year.value).isLeapYear()) aa[2] = 29; int y = this.year.value; int m = this.month.value; int d = this.day.value; for (int i = 0; i < n; i++) { d++; if (d > getDayOfMonth(y, m)) { d = 1; m++; if (m > 12) { m = 1; y++; } } } return new DateUtil(y, m, d); } public DateUtil getPreviousNDays(int n){ int y = this.year.value; int m = this.month.value; int d = this.day.value; for (int i = 0; i < n; i++) { d--; while (d < 1) { m--; if (m < 1) { m = 12; y--; } d += getDayOfMonth(y, m); } } return new DateUtil(y, m, d); } public boolean compareDates(DateUtil date){ if(date.year.value<this.year.value) return false; else if(date.year.value==this.year.value&&date.month.value<this.month.value) return false; else if(date.year.value==this.year.value&&date.month.value==this.month.value&&date.day.value<this.day.value) return false; else return true; } public boolean equalTwoDates(DateUtil date){ if(this.getDay().getValue()==date.getDay().getValue()&&this.getMonth().getValue()==date.getMonth().getValue()&&this.getYear().getValue()==date.getYear().getValue()) return true; else return false; } public int getDaysofDates(DateUtil date){ DateUtil b1=this; DateUtil b2=date; if(this.equalTwoDates(date)){ return 0; } else if(!this.compareDates(date)){ b1=date; b2=this; } int a[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; int i,j,ts=0; for(i=b1.getYear().getValue()+1;i<b2.getYear().getValue();i++){ ts=ts+365; if(new Year(i).isLeapYear()) ts++; } if(b1.getYear().getValue()==b2.getYear().getValue()&&b1.getMonth().getValue()==b2.getMonth().getValue()){//年份相同,月份相同,日不同 ts=b2.getDay().getValue()-b1.getDay().getValue(); } else if(b1.getYear().getValue()==b2.getYear().getValue()&&b1.getMonth().getValue()!=b2.getMonth().getValue()){//年份相同,月份不同 if(b1.getYear().isLeapYear()) a[2]=29; ts=ts+a[b1.getMonth().getValue()]-b1.getDay().getValue(); ts=ts+b2.getDay().getValue(); for(j=b1.getMonth().getValue()+1;j<=b2.getMonth().getValue()-1;j++) ts+=a[j]; } else if(b1.getYear().getValue()!=b2.getYear().getValue()) { ts=ts+a[b1.getMonth().getValue()]-b1.getDay().getValue(); ts=ts+b2.getDay().getValue(); for(j=b1.getMonth().getValue()+1;j<=12;j++) ts=ts+a[j]; for(j=b2.getMonth().getValue()-1;j>0;j--) ts=ts+a[j]; if(b1.getYear().isLeapYear()&&b1.getMonth().getValue()<=2) ts++; if(b2.getYear().isLeapYear()&&b2.getMonth().getValue()>2) ts++; } return ts; } public String showDate(){ return this.getYear().getValue()+"-"+this.getMonth().getValue()+"-"+this.getDay().getValue(); } } 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.year.value + "-" + date.month.value + "-" + date.day.value + " 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.year.value + "-" + date.month.value + "-" + date.day.value + " 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); } } }
三、踩坑心得
①提交时没有注意到字符串中的数字与单纯的数字不同而致错,字符串中的一与数字一之间相差48,用字符串中的一进行条件条件判断时需要注意转换。
②做题时需要先理清思路再写程序,避免逻辑上的错误。
③当发现自己当前的逻辑方法完成不了题目时,可以尝试重新换个思路,以免执行不下去。
④发现自己对字符串的相关内容不够了解,查阅字符串的相关资料学习后,对字符串的方法有一个更加深入的了解,做题时查缺补漏。
⑤对数据类型的使用不够准确,也不够了解数据的精度和必要时的数据强制转换。
四、改进建议
①题目集03的7-3中的三个类之间的耦合性较大,三个类之间的关联较大,后一个类里用了前一个类的对象,应降低类之间的耦合性,使各个类只做自己的事情。
相比于7-3,7-4的耦合性更低,三个类只处理自己本身的问题,类间联系更低,耦合性更低。
②对于多个数据需要转换,可以思考整体的一个转换关系,而不是一个一个的转换。
③对于一个问题可以思考灵活的方法,做到可扩展性,增加功能或减少功能时不必修改太多的代码,灵活的方法也不需要太多的代码解决一个问题。
五、总结
通过这三次题目集的练习,我了解了Java,掌握了Java的一些基础语法,Java的语法有些与C语言大同小异,但有许多Java独特的地方,比如最简单的输入输出,还掌握了字符串的相关内容,有字符串的查找、截取、字符串与字符数组的转换,字符串之间的比较等,还掌握了类的相关设计,对象的创建,方法的调用,但还需要更加深入地研究类与对象之间的联系,类与类之间的联系,对象与对象之间的联系。其他方面我觉得课上及课下组织方式已经非常好了,教师的教学也非常好,对于作业以及实验我也没有可以挑剔的地方。