题目集4~6的总结性Blog
一、前言
题目集四
知识点考察:字符串正则匹配,面向对象设计思想,基础类的封装和继承
题量:适中
难度:第一题偏复杂,正则表达式匹配较为复杂,需要注意逻辑处理,二三题简单,基本类的封装和继承
题目集五
知识点考察:面向对象设计思想基本类的设计,正则匹配,字符串处理,基本数组排序
题量:适中
难度:第二题一般,其他题简单
题目集六
知识点考察:正则表达式,类的继承与多态
题量:适中
难度:简单,基础正则匹配,基本类的设计
二、设计与分析
题目集四
7-1 水文数据校验及处理 (50 分)
使用Java中的字符串处理类以及正则表达式对输入字符串数据进行合法性校验及计算。(具体需求参见附件 2021-OO第04次作业-1指导书V1.0.pdf )
输入格式:
假定分水口门的数据上报时是采用人工输入的方式,每一行代表一个整点时刻的分水数据,各数据之间采用“|”符号进行分隔,每次可以输入多条数据,直到遇到用户输入“exit”为止,每一行输入数据共包含五部分:测量时间、目标水位、实际水位、开度(包含目标开度和实际开度,以“/”分隔)、流量。 各数据格式要求如下:
1.测量时间:格式为“年/月/日 时:分”,其中年份取值范围为[1,9999],“月”与“日”为一位数时之前不加“0”,日期与时间之间有一个空格,“时”与“分”之间采用冒号分隔(英文半角),“时”为一位数时之前不加“0”,“分”始终保持两位,且始终为“00”。注意:“时”数必须是24小时进制中的偶数值。
2.目标水位、实际水位、流量:均为实型数,取值范围为[1,1000), 小数点后保留1-3位小数或无小数(也无小数点)
3.目标开度、实际开度:实型数,取值范围为[1,10),必须保留2位小数,两个开度之间用“/”分隔
输出格式:
1.对输入的数据进行有效性校验,其规则如前所述,如遇到不符合规则的数据,系统应能够给出错误提示,提示规则如下:
如果每一行输入数据不是由“|”分隔的五部分,则输出:
Wrong Format
Data:输入的数据
如果某一部分数据有误,则按如下方式显示:
Row:行号,Column:列号Wrong Format
Data:输入的数据
其中,行号为输入数的行数(从1开始),列号为6个数据的序号(从1开始,最大为6,顺序参见输入数据结构说明)
1.由于人工输入数据可能存在疏忽,在每一个输入数据两端均可能存在多余的空格,程序应该能够自动过滤这些空格(不报错)。
2.如果用户未输入数据,则直接输出Max Actual Water Level和Total Water Flow的值即可(均为0)
3.若输入无误,则对数据进行如下处理:
当实际开度的值大于目标开度时,程序给出如下警告:
Row:1 GateOpening Warning
求出所输入数据中的最大实际水位值(保留2位小数),输出格式如下: Max Actual Water Level:实际水位值
根据每个整点时刻的瞬时流量求出所输入的所有时段的总流量(保留2位小数),其计算公式为(参见作业指导书):
$$p = \sum_{n=1}^N2*60*60*Flow$$
输出格式如下:
Total Water Flow:总流量值
输入样例1:
在这里给出一组输入。例如:
2015/8/2 4:00|133.8400|133.070|1.11/1.21|75.780
2015/8/2 6:00|133.840|133.080|11.11/1.11|72.8a0
2015/8/2 8:00|133.830|133.070|1.11/1.11|73.890
2015/8/2 10:00|133.820|133.080|1.11/1.11|74.380
exit
输出样例1:
在这里给出相应的输出。例如:
Row:1,Column:2Wrong Format
Data:2015/8/2 4:00|133.8400|133.070|1.11/1.21|75.780
Row:2,Column:4Wrong Format
Row:2,Column:6Wrong Format
Data:2015/8/2 6:00|133.840|133.080|11.11/1.11|72.8a0
输入样例2:
在这里给出一组输入。例如:
2015/8/5 2:00|133.800|133.080|1.11/1.11|73.870
2015/8/5 4:00|133.800|133.070|1.11/1.11|73.330
2015/8/5 6:00|133.830|133.110|1.11/1.21|70.610
2015/8/5 8:00|133.860|133.140|1.11/1.11|73.430
2015/8/5 10:00|133.91|133.15|1.11/1.11|73.06
2015/8/5 12:00|133.900|133.110|1.16/1.11|75.460
2015/8/5 14:00|133.920|133.140|1.16/1.11|77.030
2015/8/5 16:00|133.92|133.16|1.16/1.91|79.4
2015/8/5 18:00|133.940|133.170|1.16/1.11|76.810
2015/8/5 20:00|133.94|133.19|1.16/1.11|74.53
2015/8/5 22:00|133.930|133.200|1.16/1.11|74.400
2015/8/6 0:00|133.930|133.200|1.16/1.11|73.150
2015/8/6 2:00|133.930|133.180|1.16/1.11|74.830
2015/8/6 4:00|133.910|133.180|1.16/1.11| 73.270
exit
输出样例2:
在这里给出相应的输出。例如:
Row:3 GateOpening Warning
Row:8 GateOpening Warning
Max Actual Water Level:133.20
Total Water Flow:7510896.00
代码
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static boolean isLeapYear(int year) {
return (year%4==0&&year%100!=0)||year%400==0;
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
String time="(^[1-9]\\d{0,3})/([1-9]|1[0-2])/([1-9]|([12][0-9])|30|31) ([02468]|10|12|14|16|18|20|22):00";
String num="^[0-9]+(\\.[0-9]{1,3})?$";
String flowOpening="(^[0-9]+(\\.[0-9]{2}))/([0-9]+(\\.[0-9]{2}$))";
String format="(.+)\\|(.+)\\|(.+)\\|(.+)\\|(.+)";
Pattern timep=Pattern.compile(time);
Pattern nump=Pattern.compile(num);
Pattern flowOpeningp=Pattern.compile(flowOpening);
Pattern formatp=Pattern.compile(format);
String a=new String(scanner.nextLine());
int Row=1;
double Max=0;
double flow=0;
boolean flagall=true;
while (!a.equals("exit")){
if(a.equals(""))
{
a=scanner.nextLine();
continue;
}
Matcher formatm= formatp.matcher(a);
if(formatm.find())
{
boolean flag=true;
String part1=formatm.group(1).trim();
String part2=formatm.group(2).trim();
String part3=formatm.group(3).trim();
String part4=formatm.group(4).trim();
String part5=formatm.group(5).trim();
Matcher timem=timep.matcher(part1);
Matcher numm1= nump.matcher(part2);
Matcher numm2=nump.matcher(part3);
Matcher flowOpeningm=flowOpeningp.matcher(part4);
Matcher numm3= nump.matcher(part5);
if(timem.find())
{
int[] b=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
int year=Integer.parseInt(timem.group(1));
int month=Integer.parseInt(timem.group(2));
int day=Integer.parseInt(timem.group(3));
if(isLeapYear(year))
{
b[2]=29;
}else b[2]=28;
if(day>b[month])
{
System.out.println("Row:"+Row+",Column:1Wrong Format");
flagall=false;
flag=false;
}
}
else {
System.out.println("Row:"+Row+",Column:1Wrong Format");
flagall=false;
flag=false;
}
boolean flag1=true;
for(int i=0;i<part2.length();i++)
{
if(Character.isLetter(part2.charAt(i)))
{
System.out.println("Row:"+Row+",Column:2Wrong Format");
flagall=false;
flag1=false;
break;
}
}
if(flag1)
{
if(numm1.find())
{
double mubiaowater=Double.parseDouble(numm1.group());
if(part2.charAt(0)=='0')
{
System.out.println("Row:"+Row+",Column:2Wrong Format");
flagall=false;
flag=false;
}
else if(mubiaowater>=1000||mubiaowater<1)
{
System.out.println("Row:"+Row+",Column:2Wrong Format");
flagall=false;
flag=false;
}
}
else {
System.out.println("Row:"+Row+",Column:2Wrong Format");
flagall=false;
flag=false;
}
}
boolean flag2=true;
for(int i=0;i<part3.length();i++)
{
if(Character.isLetter(part3.charAt(i)))
{
System.out.println("Row:"+Row+",Column:3Wrong Format");
flagall=false;
flag=false;
flag2=false;
break;
}
}
if(flag2)
{
if(numm2.find())
{
double mubiaowater=Double.parseDouble(numm2.group());
if(part3.charAt(0)=='0')
{
System.out.println("Row:"+Row+",Column:3Wrong Format");
flagall=false;
flag=false;
}
else if(mubiaowater>=1000||mubiaowater<1)
{
System.out.println("Row:"+Row+",Column:3Wrong Format");
flagall=false;
flag=false;
}
else if(mubiaowater>=Max)
Max=mubiaowater;
}
else {
System.out.println("Row:"+Row+",Column:3Wrong Format");
flagall=false;
flag=false;
}
}
boolean flag4=false;
if(flowOpeningm.find())
{
double watar1=Double.parseDouble(flowOpeningm.group(1));
double watar2=Double.parseDouble(flowOpeningm.group(3));
if(flowOpeningm.group(1).charAt(0)=='0')
{
System.out.println("Row"+Row+",Column:4Wrong Format");
flagall=false;
flag=false;
}
else if(watar1>=10||watar1<1)
{
System.out.println("Row"+Row+",Column:4Wrong Format");
flagall=false;
flag=false;
}
if(flowOpeningm.group(3).charAt(0)=='0')
{
System.out.println("Row"+Row+",Column:5Wrong Format");
flagall=false;
flag=false;
}
else if(watar2>=10||watar2<1)
{
System.out.println("Row"+Row+",Column:5Wrong Format");
flagall=false;
flag=false;
}
if(watar1<watar2&&flag)
{
flag4=true;
}
}
boolean flag3=true;
for(int i=0;i<part5.length();i++)
{
if(Character.isLetter(part5.charAt(i)))
{
System.out.println("Row:"+Row+",Column:6Wrong Format");
flagall=false;
flag=false;
flag3=false;
break;
}
}
if(flag3)
{
if(numm3.find())
{
double liuliang=Double.parseDouble(numm3.group());
if(part5.charAt(0)=='0')
{
System.out.println("Row:"+Row+",Column:6Wrong Format");
flagall=false;
flag=false;
}
else if(liuliang>=1000||liuliang<1)
{
System.out.println("Row:"+Row+",Column:6Wrong Format");
flagall=false;
flag=false;
}
else flow+=2.0*60.0*60.0*liuliang;
}
else {
System.out.println("Row:"+Row+",Column:6Wrong Format");
flagall=false;
flag=false;
}
}
if(flag4)
{
System.out.println("Row:"+Row+" GateOpening Warning");
}
if(!flag)
{
System.out.println("Data:"+a);
}
}
else
{
System.out.println("Wrong Format");
System.out.println("Data:"+a);
}
Row++;
a=scanner.nextLine();
}
if(flagall)
{
System.out.printf("Max Actual Water Level:%.2f\n",Max);
System.out.printf("Total Water Flow:%.2f",flow);
}
}
}
代码分析图

题目思路
铸币代码看看就好,没怎么debug,有两个点没过,没花多少时间写,圈复杂度都起飞了,非常不面向对象。
这题主要考察正则表达式处理字符串,注意仔细看题目的要求,先处理格式错误再处理数据错误,如果格式错误则不处理数据错误。
1.先用正则匹配整个格式。
2.再使用gruop()将每个数据部分取出。
3.单独进行处理,注意控制输出。
7-2 日期问题面向对象设计(聚合一) (35 分)
参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

应用程序共测试三个功能:
1.求下n天
2.求前n天
3.求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):
1 year month day n //测试输入日期的下n天
2 year month day n //测试输入日期的前n天
3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
当输入有误时,输出格式如下: Wrong Format
当第一个数字为1且输入均有效,输出格式如下:
year-month-day
当第一个数字为2且输入均有效,输出格式如下:
year-month-day
当第一个数字为3且输入均有效,输出格式如下:
天数值
输入样例1:
在这里给出一组输入。例如:
3 2014 2 14 2020 6 14
结尾无空行
输出样例1:
在这里给出相应的输出。例如:
2312
结尾无空行
输入样例2:
在这里给出一组输入。例如:
2 1935 2 17 125340
结尾无空行
输出样例2:
在这里给出相应的输出。例如:
1591-12-17
结尾无空行
代码
import java.util.Scanner;
class 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(){
return (value % 4 == 0 && value % 100 != 0) || value % 400 == 0;
}
public boolean validate(){
return value <= 2050 && value >= 1900;
}
public void yearIncrement(){
value++;
}
public void yearReduction(){
value--;
}
}
//Month类
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(){
return value;
}
public Year getYear(){
return year;
}
public void setValue(int value){
this.value=value;
}
public void setYear(Year year){
this.year=year;
}
public void resetMin(){
value=1;
}
public void resetMax(){
value=12;
}
public boolean validate(){
return value >= 1 && value <= 12;
}
public void dayIncrement(){
value++;
}
public void dayReduction(){
value--;
}
}
class Day{
int value;
Month month;
int[] a ={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(){
return value;
}
public Month getMonth(){
return month;
}
public void setValue(int value){
this.value=value;
}
public void setMonth(Month value){
this.month=value;
}
public void resetMin(){
value=1;
}
public void resetMax(){
value=a[month.getValue()-1];
}
public boolean validate(){
if(this.getMonth().getYear().isLeapYear())
a[1]=29;
return value >= 1 && value <= a[month.getValue() - 1];
}
public void dayIncrement() {
value ++;
}
public void dayReduction() {
value--;
}
}
class DateUtil{
Day day;
public DateUtil(){
}
public DateUtil(int d,int m,int y){
this.day=new Day(d,m,y);
}
public Day getDay(){
return day;
}
public void setDay(Day d){
this.day=d;
}
public boolean checkInputValidity(){
return !this.getDay().getMonth().getYear().validate() || !this.getDay().getMonth().validate() || !day.validate();
}
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 return date.getDay().getMonth().getYear().getValue() != this.getDay().getMonth().getYear().getValue() || date.getDay().getMonth().getValue() != this.getDay().getMonth().getValue() || date.getDay().getValue() > this.getDay().getValue();
}
public boolean equalTwoDates(DateUtil date){
return this.getDay().getValue() == date.getDay().getValue() && this.getDay().getMonth().getValue() == date.getDay().getMonth().getValue() && this.getDay().getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue();
}
public String showDate(){
return this.getDay().getMonth().getYear().getValue()+"-"+this.getDay().getMonth().getValue()+"-"+this.getDay().getValue();
}
public boolean isLeapYear(int year){
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
public DateUtil getNextNDays(int n){
int[] a=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
int day =this.getDay().getValue();
int month =this.getDay().getMonth().getValue();
int year=this.getDay().getMonth().getYear().getValue();
if(isLeapYear(year))
a[2]=29;
n+=day;
while (n>a[month])
{
if(isLeapYear(year))
a[2]=29;
else a[2]=28;
n-=a[month];
if(month>=12)
{
year++;
month=1;
}
else month++;
}
day=n;
return new DateUtil(year,month,day);
}
//求前n天
public DateUtil getPreviousNDays(int n){
int[] a=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
int day =this.getDay().getValue();
int month =this.getDay().getMonth().getValue();
int year=this.getDay().getMonth().getYear().getValue();
if(isLeapYear(year))
a[2]=29;
if(n>=day)
{
n-=day;
if(month<=1)
{
year--;
month=12;
}
else month--;
while (n>a[month])
{
if(isLeapYear(year))
a[2]=29;
else a[2]=28;
n-=a[month];
if(month<=1)
{
year--;
month=12;
}
else month--;
}
day=a[month]-n;
}
else day-=n;
return new DateUtil(year,month,day);
}
//求两个日期之间的天数
public int getDaysofDates(DateUtil date){
int[] a=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
int day =this.getDay().getValue();
int month =this.getDay().getMonth().getValue()-1;
int year=this.getDay().getMonth().getYear().getValue();
int day1 =date.getDay().getValue();
int month1 =date.getDay().getMonth().getValue()-1;
int year1=date.getDay().getMonth().getYear().getValue();
int num1=day,num2=day1;
if(isLeapYear(year))
a[2]=29;
else a[2]=28;
while (month>0)
{
num1+=a[month--];
}
year--;
while (year>1800)
{
if(isLeapYear(year))
num1+=366;
else num1+=365;
year--;
}
if(isLeapYear(year1))
a[2]=29;
else a[2]=28;
while (month1>0)
{
num2+=a[month1--];
}
year1--;
while (year1>1800)
{
if(isLeapYear(year1))
num2+=366;
else num2+=365;
year1--;
}
return Math.abs(num2-num1);
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int a,b;
a=scanner.nextInt();
DateUtil c=new DateUtil(scanner.nextInt(),scanner.nextInt(),scanner.nextInt());
if(a==1){//求下n天
b=scanner.nextInt();//输入n
if(c.checkInputValidity() ||b<0){//如果数据不合法
System.out.println("Wrong Format");
}
else {
System.out.println(c.getNextNDays(b).showDate());
}
}
else if(a==2){
b=scanner.nextInt();//输入n
if(c.checkInputValidity() ||b<0){//如果数据不合法
System.out.println("Wrong Format");
}
else
System.out.println(c.getPreviousNDays(b).showDate());
}
else if(a==3){
DateUtil d=new DateUtil(scanner.nextInt(),scanner.nextInt(),scanner.nextInt());
if(c.checkInputValidity() || d.checkInputValidity()){//如果数据不合法
System.out.println("Wrong Format");
}
else
System.out.println(c.getDaysofDates(d));
}
else
System.out.println("Wrong Format");
}
}
代码分析图

题目思路
编写程序,实现图形类的继承,并定义相应类对象并进行测试。
1.类Shape,无属性,有一个返回0.0的求图形面积的公有方法public double getArea();//求图形面积
2.类Circle,继承自Shape,有一个私有实型的属性radius(半径),重写父类继承来的求面积方法,求圆的面积
3.类Rectangle,继承自Shape,有两个私有实型属性width和length,重写父类继承来的求面积方法,求矩形的面积
4.类Ball,继承自Circle,其属性从父类继承,重写父类求面积方法,求球表面积,此外,定义一求球体积的方法public double getVolume();//求球体积
5.类Box,继承自Rectangle,除从父类继承的属性外,再定义一个属性height,重写父类继承来的求面积方法,求立方体表面积,此外,定义一求立方体体积的方法public double getVolume();//求立方体体积
6.注意:
每个类均有构造方法,且构造方法内必须输出如下内容:Constructing 类名
每个类属性均为私有,且必须有getter和setter方法(可用Eclipse自动生成)
输出的数值均保留两位小数
主方法内,主要实现四个功能(1-4): 从键盘输入1,则定义圆类,从键盘输入圆的半径后,主要输出圆的面积; 从键盘输入2,则定义矩形类,从键盘输入矩形的宽和长后,主要输出矩形的面积; 从键盘输入3,则定义球类,从键盘输入球的半径后,主要输出球的表面积和体积; 从键盘输入4,则定义立方体类,从键盘输入立方体的宽、长和高度后,主要输出立方体的表面积和体积;
假如数据输入非法(包括圆、矩形、球及立方体对象的属性不大于0和输入选择值非1-4),系统输出Wrong Format
输入格式:
共四种合法输入
1 圆半径
2 矩形宽、长
3 球半径
4 立方体宽、长、高
输出格式:
按照以上需求提示依次输出
输入样例1:
在这里给出一组输入。例如:
1 1.0
结尾无空行
输出样例1:
在这里给出相应的输出。例如:
Constructing Shape
Constructing Circle
Circle's area:3.14
结尾无空行
输入样例2:
在这里给出一组输入。例如:
4 3.6 2.1 0.01211
结尾无空行
输出样例2:
在这里给出相应的输出。例如:
Constructing Shape
Constructing Rectangle
Constructing Box
Box's surface area:15.26
Box's volume:0.09
结尾无空行
代码
import java.util.Scanner;
class Shape
{
public Shape()
{
System.out.println("Constructing Shape");
}
public double getArea()
{
return 0.0;
}
}
class Circle extends Shape
{
public Circle()
{
System.out.println("Constructing Circle");
}
private double radius;
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public double getArea() {
return Math.PI*radius*radius;
}
}
class Rectangle extends Shape
{
public Rectangle()
{
System.out.println("Constructing Rectangle");
}
private double width;
private double length;
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getArea() {
return width*length;
}
}
class Ball extends Circle
{
public Ball()
{
System.out.println("Constructing Ball");
}
public double getArea() {
return 4.0*super.getArea();
}
public double getVolume()
{
return 4.0/3.0*Math.pow(getRadius(),3)*Math.PI;
}
}
class Box extends Rectangle
{
public Box()
{
System.out.println("Constructing Box");
}
private double height;
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getVolume()
{
return height*super.getArea();
}
public double getArea() {
return 2*(getWidth()*getLength()+getWidth()*height+getLength()*height);
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int type=scanner.nextInt();
switch (type) {
case 1 :
double r = scanner.nextDouble();
if (r < 0)
System.out.println("Wrong Format");
else {
Circle circle = new Circle();
circle.setRadius(r);
System.out.printf("Circle's area:%.2f", circle.getArea());
}
break;
case 2 :
double w = scanner.nextDouble();
double l = scanner.nextDouble();
if (w < 0 || l < 0)
System.out.println("Wrong Format");
else {
Rectangle rectangle = new Rectangle();
rectangle.setLength(l);
rectangle.setWidth(w);
System.out.printf("Rectangle's area:%.2f%n", rectangle.getArea());
}
break;
case 3 :
double r2 = scanner.nextDouble();
if (r2 < 0.0)
System.out.println("Wrong Format");
else {
Ball ball = new Ball();
ball.setRadius(r2);
System.out.printf("Ball's surface area:%.2f%n", ball.getArea());
System.out.printf("Ball's volume:%.2f%n", ball.getVolume());
}
break;
case 4 :
w = scanner.nextDouble();
l = scanner.nextDouble();
double h = scanner.nextDouble();
if (w < 0 || l < 0 || h < 0)
System.out.println("Wrong Format");
else {
Box box = new Box();
box.setHeight(h);
box.setWidth(w);
box.setLength(l);
System.out.printf("Box's surface area:%.2f%n", box.getArea());
System.out.printf("Box's volume:%.2f%n", box.getVolume());
}
break;
default : System.out.println("Wrong Format");
}
}
}
代码分析图

题目思路
照着类图写就行,没说什么好说的。
题目集五
7-5 日期问题面向对象设计(聚合二) (40 分)
参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

应用程序共测试三个功能:
1.求下n天
2.求前n天
3.求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
输入格式:
有三种输入方式(以输入的第一个数字划分[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
结尾无空行
代码
import java.util.Scanner;
class 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(){
return (value % 4 == 0 && value % 100 != 0) || value % 400 == 0;
}
public boolean validate(){
return value <= 2020 && value >= 1820;
}
public void yearIncrement(){
value++;
}
public void yearReduction(){
value--;
}
}
//Month类
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(){
return value;
}
public Year getYear(){
return year;
}
public void setValue(int value){
this.value=value;
}
public void setYear(Year year){
this.year=year;
}
public void resetMin(){
value=1;
}
public void resetMax(){
value=12;
}
public boolean validate(){
return value >= 1 && value <= 12;
}
public void dayIncrement(){
value++;
}
public void dayReduction(){
value--;
}
}
class Day{
int value;
Month month;
int[] a ={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(){
return value;
}
public Month getMonth(){
return month;
}
public void setValue(int value){
this.value=value;
}
public void setMonth(Month value){
this.month=value;
}
public void resetMin(){
value=1;
}
public void resetMax(){
value=a[month.getValue()-1];
}
public boolean validate(){
if(this.getMonth().getYear().isLeapYear())
a[1]=29;
return value >= 1 && value <= a[month.getValue() - 1];
}
public void dayIncrement() {
value ++;
}
public void dayReduction() {
value--;
}
}
class DateUtil{
Day day;
public DateUtil(){
}
public DateUtil(int d,int m,int y){
this.day=new Day(d,m, y);
}
public Day getDay(){
return day;
}
public void setDay(Day d){
this.day=d;
}
public boolean checkInputValidity(){
return !this.getDay().getMonth().getYear().validate() || !this.getDay().getMonth().validate() || !day.validate();
}
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 return date.getDay().getMonth().getYear().getValue() != this.getDay().getMonth().getYear().getValue() || date.getDay().getMonth().getValue() != this.getDay().getMonth().getValue() || date.getDay().getValue() > this.getDay().getValue();
}
public boolean equalTwoDates(DateUtil date){
return this.getDay().getValue() == date.getDay().getValue() && this.getDay().getMonth().getValue() == date.getDay().getMonth().getValue() && this.getDay().getMonth().getYear().getValue() == date.getDay().getMonth().getYear().getValue();
}
public String showDate(){
return this.getDay().getMonth().getYear().getValue()+"-"+this.getDay().getMonth().getValue()+"-"+this.getDay().getValue();
}
public boolean isLeapYear(int year){
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
public DateUtil getNextNDays(int n){
int[] a=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
int day =this.getDay().getValue();
int month =this.getDay().getMonth().getValue();
int year=this.getDay().getMonth().getYear().getValue();
System.out.print(year+"-"+month+"-"+day+" next "+n+" days is:");
if(isLeapYear(year))
a[2]=29;
while (n>a[month])
{
if(isLeapYear(year))
a[2]=29;
else a[2]=28;
n-=a[month];
if(month>=12)
{
year++;
month=1;
}
else month++;
}
n+=day;
while (n>a[month])
{
if(isLeapYear(year))
a[2]=29;
else a[2]=28;
n-=a[month];
if(month>=12)
{
year++;
month=1;
}
else month++;
}
day=n;
return new DateUtil(year,month,day);
}
//求前n天
public DateUtil getPreviousNDays(int n){
int[] a=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
int day =this.getDay().getValue();
int month =this.getDay().getMonth().getValue();
int year=this.getDay().getMonth().getYear().getValue();
System.out.print(year+"-"+month+"-"+day+" previous "+n+" days is:");
if(isLeapYear(year))
a[2]=29;
if(n>=day)
{
n-=day;
if(month<=1)
{
year--;
month=12;
}
else month--;
while (n>a[month])
{
if(isLeapYear(year))
a[2]=29;
else a[2]=28;
n-=a[month];
if(month<=1)
{
year--;
month=12;
}
else month--;
}
day=a[month]-n;
}
else day-=n;
return new DateUtil(year,month,day);
}
//求两个日期之间的天数
public int getDaysofDates(DateUtil date){
int[] a=new int[]{0,31,28,31,30,31,30,31,31,30,31,30,31};
int day =this.getDay().getValue();
int month =this.getDay().getMonth().getValue()-1;
int year=this.getDay().getMonth().getYear().getValue();
int day1 =date.getDay().getValue();
int month1 =date.getDay().getMonth().getValue()-1;
int year1=date.getDay().getMonth().getYear().getValue();
int num1=day,num2=day1;
System.out.print("The days between "+year+"-"+(month+1)+"-"+day+" and "+year1+"-"+(month1+1)+"-"+day1+" are:");
if(isLeapYear(year))
a[2]=29;
while (month>0)
{
num1+=a[month--];
}
year--;
while (year>0)
{
if(isLeapYear(year))
num1+=366;
else num1+=365;
year--;
}
if(isLeapYear(year1))
a[2]=29;
else a[2]=28;
while (month1>0)
{
num2+=a[month1--];
}
year1--;
while (year1>0)
{
if(isLeapYear(year1))
num2+=366;
else num2+=365;
year1--;
}
return Math.abs(num2-num1);
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
int a,b;
a=scanner.nextInt();
DateUtil c=new DateUtil(scanner.nextInt(),scanner.nextInt(),scanner.nextInt());
if(a==1){//求下n天
b=scanner.nextInt();//输入n
if(c.checkInputValidity() ||b<0){//如果数据不合法
System.out.println("Wrong Format");
}
else {
System.out.println(c.getNextNDays(b).showDate());
}
}
else if(a==2){
b=scanner.nextInt();//输入n
if(c.checkInputValidity() ||b<0){//如果数据不合法
System.out.println("Wrong Format");
}
else
System.out.println(c.getPreviousNDays(b).showDate());
}
else if(a==3){
DateUtil d=new DateUtil(scanner.nextInt(),scanner.nextInt(),scanner.nextInt());
if(c.checkInputValidity() || d.checkInputValidity()){//如果数据不合法
System.out.println("Wrong Format");
}
else
System.out.println(c.getDaysofDates(d));
}
else
System.out.println("Wrong Format");
}
}
代码分析图

题目思路
和题目集四7-3一样
题目集六
7-5 图形继承与多态 (50 分)
掌握类的继承、多态性及其使用方法。具体需求参见作业指导书。
输入格式:
从键盘首先输入三个整型值(例如a b c),分别代表想要创建的Circle、Rectangle及Triangle对象的数量,然后根据图形数量继续输入各对象的属性值(均为实型数),数与数之间可以用一个或多个空格或回车分隔。
输出格式:
1.如果图形数量非法(小于0)或图形属性值非法(数值小于0以及三角形三边关系),则输出Wrong Format。
2.如果输入合法,则正常输出,输出内容如下(输出格式见输入输出示例):
各个图形的面积;
所有图形的面积总和;
排序后的各个图形面积;
再次所有图形的面积总和。
输入样例1:
在这里给出一组输入。例如:
1 1 1 2.3 3.2 3.2 6.5 3.2 4.2
结尾无空行
输出样例1:
在这里给出相应的输出。例如:
Original area:
16.62 10.24 5.68
Sum of area:32.54
Sorted area:
5.68 10.24 16.62
Sum of area:32.54
结尾无空行
输入样例2:
在这里给出一组输入。例如:
0 2 2 2.3 2.5 56.4 86.5 64.3 85.6 74.6544 3.2 6.1 4.5
结尾无空行
输出样例2:
在这里给出相应的输出。例如:
Original area:
5.75 4878.60 2325.19 7.00
Sum of area:7216.54
Sorted area:
5.75 7.00 2325.19 4878.60
Sum of area:7216.54
结尾无空行
代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
abstract class Shape {
public Shape() {
}
abstract public double getArea();
abstract public boolean validate();
}
class Circle extends Shape {
private double radius;
Circle(double radius) {
this.radius = radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public double getArea() {
return Math.PI * radius * radius;
}
public boolean validate() {
return radius > 0;
}
}
class Rectangle extends Shape {
private double width;
private double length;
Rectangle(double width,double length)
{
this.width=width;
this.length=length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getArea() {
return width * length;
}
public boolean validate() {
return length > 0 && width > 0;
}
}
class Triangle extends Shape {
private double side1;
private double side2;
private double side3;
public boolean validate() {
return side3 + side2 > side1 && side2 + side1 > side3 & side1 + side3 > side2;
}
public double getArea() {
double p = (side1 + side2 + side3) / 2;
return Math.sqrt(p * (p - side1) * (p - side2) * (p - side3));
}
Triangle(double side1, double side2, double side3) {
this.side1 = side1;
this.side2 = side2;
this.side3 = side3;
}
public double getSide1() {
return side1;
}
public double getSide2() {
return side2;
}
public double getSide3() {
return side3;
}
public void setSide1(double side1) {
this.side1 = side1;
}
public void setSide2(double side2) {
this.side2 = side2;
}
public void setSide3(double side3) {
this.side3 = side3;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
ArrayList<Double> arrayList = new ArrayList<>();
int n1 = scanner.nextInt();
int n2 = scanner.nextInt();
int n3 = scanner.nextInt();
if (n1 < 0 || n2 < 0 || n3 < 0) {
System.out.println("Wrong Format");
} else {
for (int i = 0; i < n1; i++) {
double radius = scanner.nextDouble();
Circle circle=new Circle(radius);
if(!circle.validate())
{
System.out.println("Wrong Format");
System.exit(0);
}
else {
arrayList.add(circle.getArea());
}
}
for (int i=0;i<n2;i++)
{
double length=scanner.nextDouble();
double width=scanner.nextDouble();
Rectangle rectangle=new Rectangle(length,width);
if(!rectangle.validate())
{
System.out.println("Wrong Format");
System.exit(0);
}
else {
arrayList.add(rectangle.getArea());
}
}
for (int i=0;i<n3;i++)
{
double side1=scanner.nextDouble();
double side2=scanner.nextDouble();
double side3=scanner.nextDouble();
Triangle triangle=new Triangle(side1,side2,side3);
if(!triangle.validate())
{
System.out.println("Wrong Format");
System.exit(0);
}
else {
arrayList.add(triangle.getArea());
}
}
double area=0;
System.out.println("Original area:");
for (Double aDouble : arrayList) {
System.out.printf("%.2f ", aDouble);
area += aDouble;
}
System.out.printf("\nSum of area:%.2f",area);
System.out.println("\nSorted area:");
Collections.sort(arrayList);
for (Double aDouble : arrayList) {
System.out.printf("%.2f ", aDouble);
}
System.out.printf("\nSum of area:%.2f",area);
}
}
}
代码分析图

题目思路
照着类图写,用ArrrayList存储面积数据,注意排序和输出格式即可。
7-6 实现图形接口及多态性 (30 分)
编写程序,使用接口及类实现多态性,类图结构如下所示:

其中:
GetArea为一个接口,无属性,只有一个GetArea(求面积)的抽象方法;
Circle及Rectangle分别为圆类及矩形类,分别实现GetArea接口
要求:在Main类的主方法中分别定义一个圆类对象及矩形类对象(其属性值由键盘输入),使用接口的引用分别调用圆类对象及矩形类对
象的求面积的方法,直接输出两个图形的面积值。(要求只保留两位小数)
输入格式:
从键盘分别输入圆的半径值及矩形的宽、长的值,用空格分开。
输出格式:
如果输入的圆的半径值及矩形的宽、长的值非法(≤0),则输出Wrong Format
如果输入合法,则分别输出圆的面积和矩形的面积值(各占一行),保留两位小数。
输入样例1:
在这里给出一组输入。例如:
2 3.6 2.45
结尾无空行
输出样例1:
在这里给出相应的输出。例如:
12.57
8.82
结尾无空行
输入样例2:
在这里给出一组输入。例如:
9 0.5 -7.03
结尾无空行
输出样例2:
在这里给出相应的输出。例如:
Wrong Format
结尾无空行
代码
import java.util.Scanner;
interface GetArea {
public double getArea();
}
class Circle1 implements GetArea {
private double radius;
public Circle1() {
}
public Circle1(double r) {
this.radius = r;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
//计算圆面积
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle1 implements GetArea {
private double length, width;
public Rectangle1() {
}
public Rectangle1(double a, double b) {
this.length = a;
this.width = b;
}
public double getLength() {
return length;
}
public double getWidth() {
return width;
}
public void setLength(double length) {
this.length = length;
}
public void setWidth(double width) {
this.width = width;
}
public double getArea() {
return length * width;
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double radius = scanner.nextDouble();
double length = scanner.nextDouble();
double width = scanner.nextDouble();
if(radius<=0||length<=0||width<=0){
System.out.println("Wrong Format");
System.exit(0);
}
GetArea c=new Circle1(radius);
GetArea r=new Rectangle1(length,width);
System.out.printf("%.2f\n",c.getArea());
System.out.printf("%.2f\n",r.getArea());
}
}
代码分析图

题目思路
照着类图写就行没什么好说的。
题目集4(7-2)、题目集5(7-5)两种日期类聚合设计的优劣比较
7-2
对年月日进行了逐层的封装,使数据结构层次更加分明,加强了年月日类的联系,但各种数据和方法的调用较为麻烦,调用或取出class day中的一个方法或数据需要经过三层类的逐层调用,操作上更加复杂,也导致代码可读性降低,同时占用更加多的内存呢
7-5
对年月日类进行分开封装,整合进类DateUtil,调用每个类中的方法和数据更加方便,也节省更多的内存空间
题目集4(7-3)、题目集6(7-5、7-6)三种渐进式图形继承设计的思路与技术运用
三道题目逐层渐进,题目集4(7-3)对类进行了父子类的继承使类的层次更加分明,题目集6(7-5)使用了抽象类和抽象方法(abstract),整合了各个类中相同类型的方法,题目集6(7-6)将几个类整合成了一个接口,去除了冗余的方法,使调用更加直接,代码的作用一目了然。
对三次题目集中用到的正则表达式技术的分析总结
写正则时注意每个字符到底要匹配什么,使用|时注意括号的位置,仔细的一个一个匹配,否则一旦出现错误,匹配的字符串复杂,正则表达式很长的情况下,就很难找到错误出在哪里。
题目集5(7-4)中Java集合框架应用的分析总结
题目集5(7-4)要求用List、Map、Set接口三者中至少一个,List实现数据的插入,Map可用于关键字的排序,同时可以将每个关键字的出现次数进行匹配计数。
三、踩坑心得
题目集四7-1 水文数据校验及处理
注意仔细看题目的要求,先处理格式错误再处理数据错误,如果格式错误则不处理数据错误。
题目集五7-4 统计Java程序中关键词的出现次数
最后一个测试点好像说是有误,一定长度之后部分关键字不做匹配
四、改进建议
题目集四7-1 水文数据校验及处理 写的圈复杂度过高,应该将各种方法进行封装,使代码更加简介。
题目集五7-4 7-4 统计Java程序中关键词的出现次数 没有对关键字进行排序而是直接导入排好了的字符串数组,对方法没有进行封装,直接都写在了Main里。
五、总结
通过这三个题目集,学会了Map的用法,加深了对正则表达式的体会和理解,加深了对封装和多态的理解
封装即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员
多态就是抽象化的一种体现,把一系列具体事务的共同点抽象出来,再通过这个抽象的事物,与不同的具体事物进行对话
对于正则表达式的使用还不熟练,还需要进行练习。
Map和Set的使用还需要进行更多的学习

浙公网安备 33010602011771号