第二次博客作业
三次作业总结
前言
1、第4次作业题量较少,但第一题难度明显偏高,也是涉及到正则表达式,以及实体类,业务类的运用;第二题就难度适中,运用聚合的思想,将代码效率最大化;第三题难度偏易,图像继承是对于父类子类的简单入门应用;
2、第5次作业题量适中,整体难度适中,但第二题有点棘手,是对正则表达式的再次升级运用,其中还需要进行map,set等接口的运用;其他几道题目就是对基本知识的复习考查,其中7-5和第四次作业7-2类似,也是运用聚合的思想,后面两道题目就是对于排序的应用
3、题目集6题量依旧上升,难度平持与上一次,前四道题是对正则以及排序方式的复习,将基本的正则表达式的运用基础打牢,后续第五道题则是对题目集4图像继承的升级运用,以多态为思想基础进行编程;第六题则是对接口的使用进行了入门引导。
分析合集
1、题目集4(7-2)
参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] ,
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
注意:严禁使用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且输入均有效,输出格式如下:
天数值
设计与分析
相应类图:

SourceMonitor的生成报表:

这道题其实就是前面几道题目的升级,不过这道题要用到聚合类的思想,这对于处理各种不同类型的日期来说非常有帮助。通过构建DateUtil类对处理结果进行集成操作,再由此衍生出Year类,Month类,Day类,进行不同的处理从而提高了代码的复用性。其中对于日期的处理又和前面的题目不太一样,涉及的范围更广:
(1)求下一天日期,这次所求日期范围更大,所以分成所给年份之内还是之外来进行处理:
public DateUtil getNextNDays(int n) {
int y=0,m=0,d=0;
if(n>Last(this)) {
y=this.getDay().getMonth().getYear().getValue()+1;
int allyear=365;
if(new Year(y).isLeapYear())
allyear++;
n=n-Last(this);
while(n-allyear>0) {
n=n-allyear;
allyear=365;
y++;
if(new Year(y).isLeapYear())
allyear++;
}
if(new Year(y).isLeapYear())
a[2]=29;
for(m=1;n-a[m]>0;m++) {
n=n-a[m];
}
d=n;
}
else {
y=this.day.getMonth().getYear().getValue();
if(this.getDay().getMonth().getYear().isLeapYear()) {
a[2]=29;
}
if(a[this.day.getMonth().getValue()]-this.getDay().getValue()>=n) {
m=this.day.getMonth().getValue();
d=this.getDay().getValue()+n;
}
else {
m=this.getDay().getMonth().getValue()+1;
n=n-a[this.getDay().getMonth().getValue()]+this.getDay().getValue();
while(n-a[m]>=0){
n=n-a[m];
m++;
}
d=n;
}
}
return new DateUtil(y,m,d);
}
(2)求前n天日期,同上
(3)求两个日期相差的天数,先求出两个日期所差年份,来通过月份和日期来逐个相加:
public int getDaysoftDates(DateUtil date) {
int com=0;
if(this.equalTwoDates(date))
return 0;
DateUtil small=this;
DateUtil big=date;
if(!this.compareDates(date)) {
big=this;
small=date;
}
int i=small.getDay().getMonth().getYear().getValue()+1;
while(i<big.getDay().getMonth().getYear().getValue())
{
com=com+365;
if(new Year(i).isLeapYear())
com++;
i++;
}
if(small.getDay().getMonth().getYear().getValue()==big.getDay().getMonth().getYear().getValue()&&small.getDay().getMonth().getValue()==big.getDay().getMonth().getValue()) {
com=com+big.getDay().getValue()-small.getDay().getValue();
}
else if(small.getDay().getMonth().getYear().getValue()==big.getDay().getMonth().getYear().getValue()&&small.getDay().getMonth().getValue()!=big.getDay().getMonth().getValue()) {
if(small.getDay().getMonth().getYear().isLeapYear())
a[2]=29;
com=com+a[small.getDay().getMonth().getValue()]-small.getDay().getValue()+big.getDay().getValue();
for(i=small.getDay().getMonth().getValue()+1;i<big.getDay().getMonth().getValue();i++) {
com+=a[i];
}
}
else if(small.getDay().getMonth().getYear().getValue()!=big.getDay().getMonth().getYear().getValue()){
com+=Last(small)+365-Last(big);
if(big.getDay().getMonth().getYear().isLeapYear())
com++;
}
return com;
}
采坑心得
一个是对于聚合之间的关系不太明白,没有搞清楚怎么获取年月日,仔细看了书才明白聚合的思想;二是对于日期的校验,一开始一个月越界的测试点老是过不去,后面才明白校验日期时,由于代码的局限性,总是会先校验日,然后再是月和年,而这样的话程序的逻辑性就出现了问题,所以我直接在main函数中加了对month的校验。
改进建议
需要改进的方向,是对于年,月,日有着集成的处理方式,在对代码的复用性下,分门别类的处理较连贯性处理更具可视性与可维护性。
2、题目集5(7-5)
参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
注意:严禁使用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-mon
设计与分析
相应类图:

SourceMonitor的生成报表:

该题目较上一个题目,虽都同为聚合类型,但聚合的方式不同。其中大体聚合方式便是分开独立处理年,月,日,最后集成于DateUtil完成是输出结果的集成效果。
优劣比较
聚合一:该聚合方式就像一个链条,每个类的独立性不高,年月日这三个类由于都有公共属性,在定义了year中的value属性之后,在月这个类就中要加上Day型的day属性,month和day同理。因此在DateUtil类的方法中想要调用年月日时就得借用月和日中的属性来完成,这样做会导致程序的执行效率不高,类和类之间的关联性较强,不利于程序的复用。
聚合二:第二次聚合其中心是DateUtil类,该类连结着Year类,Month类,Day类,其中数据处理类似于年月日独立处理,初始结果集成在DateUtil类中,最终得到最后的输出结果,代码操作更为直接可观。
3、题目集4(7-3)
编写程序,实现图形类的继承,并定义相应类对象并进行测试。
- 类Shape,无属性,有一个返回0.0的求图形面积的公有方法
public double getArea();//求图形面积 - 类Circle,继承自Shape,有一个私有实型的属性radius(半径),重写父类继承来的求面积方法,求圆的面积
- 类Rectangle,继承自Shape,有两个私有实型属性width和length,重写父类继承来的求面积方法,求矩形的面积
- 类Ball,继承自Circle,其属性从父类继承,重写父类求面积方法,求球表面积,此外,定义一求球体积的方法
public double getVolume();//求球体积 - 类Box,继承自Rectangle,除从父类继承的属性外,再定义一个属性height,重写父类继承来的求面积方法,求立方体表面积,此外,定义一求立方体体积的方法
public double getVolume();//求立方体体积 - 注意:
- 每个类均有构造方法,且构造方法内必须输出如下内容:
Constructing 类名 - 每个类属性均为私有,且必须有getter和setter方法(可用Eclipse自动生成)
- 输出的数值均保留两位小数
主方法内,主要实现四个功能(1-4): 从键盘输入1,则定义圆类,从键盘输入圆的半径后,主要输出圆的面积; 从键盘输入2,则定义矩形类,从键盘输入矩形的宽和长后,主要输出矩形的面积; 从键盘输入3,则定义球类,从键盘输入球的半径后,主要输出球的表面积和体积; 从键盘输入4,则定义立方体类,从键盘输入立方体的宽、长和高度后,主要输出立方体的表面积和体积;
假如数据输入非法(包括圆、矩形、球及立方体对象的属性不大于0和输入选择值非1-4),系统输出Wrong Format
输入格式:
共四种合法输入
- 1 圆半径
- 2 矩形宽、长
- 3 球半径
- 4 立方体宽、长、高
输出格式:
按照以上需求提示依次输出
设计与分析
相应类图:

SourceMonitor的生成报表:

这道题其实就是继承的简单应用,相对来说比较基础。主要思想就是父类,子类的构建,通过在父类中写出主要的功能方法代码,再在各个子类中复写出同名的方法,给予不同的计算形式。但要注意对数据的合法性校验,输出的格式要保留两位小数。
4、题目集6(7-5)
掌握类的继承、多态性及其使用方法。具体需求参见作业指导书。
输入格式:
从键盘首先输入三个整型值(例如a b c),分别代表想要创建的Circle、Rectangle及Triangle对象的数量,然后根据图形数量继续输入各对象的属性值(均为实型数),数与数之间可以用一个或多个空格或回车分隔。
输出格式:
- 如果图形数量非法(小于0)或图形属性值非法(数值小于0以及三角形三边关系),则输出
Wrong Format。 - 如果输入合法,则正常输出,输出内容如下(输出格式见输入输出示例):
- 各个图形的面积;
- 所有图形的面积总和;
- 排序后的各个图形面积;
- 再次所有图形的面积总和。
输入样例1:
在这里给出一组输入。例如:
1 1 1 2.3 3.2 3.2 6.5 3.2 4.2
相应类图:

SourceMonitor的生成报表:

这道题相较于上一题,增加了多态的概念。每种图形求面积的方法不一样,而这正好符合多态的思想,对求面积的不同表现形式。
定义父类:
abstract class Shape{
public abstract boolean validate();
public abstract double getArge();
}
子类对父类方法的重写:(其他子类类似)
class Rectangle extends Shape{
double width;
double length;
@Override
public boolean validate() {
// TODO Auto-generated method stub
if(width>0&&length>0)
return true;
else
return false;
}
public Rectangle(double width,double length) {
this.width = width;
this.length = length;
}
@Override
public double getArge() {
// TODO Auto-generated method stub
return width*length;
}
}
在对对象的存放中,直接利用数组类的方法来存放对象:
double[] number=new double[C+R+T];
Circle[] circle=new Circle[C];
Rectangle[] rectangle=new Rectangle[R];
Triangle[] triangle=new Triangle[T];
对于计算出来的面积,也利用数组来存放,便于后期的排序。
采坑心得
一开始总有一个数据效验的测试点过不了,仔细检查才发现是因为在对图形数量进行效验前先创建了存放面积的数组,导致一直过不去,所以在书写代码时,一定要注意逻辑的合理性。
5、题目集6(7-6)
编写程序,使用接口及类实现多态性,类图结构如下所示:
其中:
- GetArea为一个接口,无属性,只有一个GetArea(求面积)的抽象方法;
- Circle及Rectangle分别为圆类及矩形类,分别实现GetArea接口
- 要求:在Main类的主方法中分别定义一个圆类对象及矩形类对象(其属性值由键盘输入),使用接口的引用分别调用圆类对象及矩形类对象的求面积的方法,直接输出两个图形的面积值。(要求只保留两位小数)
输入格式:
从键盘分别输入圆的半径值及矩形的宽、长的值,用空格分开。
输出格式:
- 如果输入的圆的半径值及矩形的宽、长的值非法(≤0),则输出
Wrong Format - 如果输入合法,则分别输出圆的面积和矩形的面积值(各占一行),保留两位小数。
设计与分析
相应类图:

SourceMonitor的生成报表:

这道题是接口的入门应用,接口不能创建对象,但是可以被实现,而实现接口的类要实现接口中所有的抽象方法。
定义接口:
interface GetArea{
public abstract double GetArea();
}
定义实现类:(其他实现类类似)
class Circle implements GetArea{
private double radius;
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double GetArea() {
return Math.PI*radius*radius;
}
public Circle(double radius) {
this.radius=radius;
}
}
接口的优点是多方面的,接口能够让代码更规范,可以给开发人员更清晰的指示,一个接口可以去实现一系列的功能。而且接口可以加强代码的可维护性,当程序需要改变的时候,可以做到只改变一个类而不改变接口。
正则表达式技术的分析总结
(1)水文数据校验及处理:
这道题主要是处理字符串并且对输入的字符串数据进行合法性检验,难点在于从字符串中提取数据以及对日期的合法性检测
数据的合法性校验:
"(((([1-9])|([1-9][0-9])|([1-9][0-9]{2})|([1-9][0-9]{3})/((([13578]|1[02])/([1-9]|[12][0-9]|3[01]))|(([469]|11)/([1-9]|[12][0-9]|30))|(2/([1-9]|[1][0-9]|2[0-8])))))|(((([1-9][0-9])(0[48]|[2468][048]|[13579][26]))|(([48]|[2468][048]|[3579][26])00))/2/29)) ((([02468])|(1[02468])|(2[02])):00)";//匹配时间
"([1-9][0-9]{0,2}(\\.[0-9]{1,3})?)";//匹配水位和匹配流量
"([1-9]\\.[0-9]{2})";//匹配开度
(2)正则表达式训练
"^[1-9]\\d{4,14}$"//QQ号校验
"^(\\d|\\w){4}$"//验证码校验
"^(20201[1-7]|20207[1-3]|20208[1-2])(0[1-9]|[1-3][0-9]|40)$"//学号校验
在Java中也可以通过处理字符串的方式达到检索,替换文本字符串的目的,但是有了正则表达式写代码更加简洁,通常两三行代码就可以达到目的。通过以上题目也可以了解到正则表达式的强大。
6、题目集5(7-4)
编写程序统计一个输入的Java源码中关键字(区分大小写)出现的次数。说明如下:
- Java中共有53个关键字(自行百度)
- 从键盘输入一段源码,统计这段源码中出现的关键字的数量
- 注释中出现的关键字不用统计
- 字符串中出现的关键字不用统计
- 统计出的关键字及数量按照关键字升序进行排序输出
- 未输入源码则认为输入非法
输入格式:
输入Java源码字符串,可以一行或多行,以exit行作为结束标志
输出格式:
- 当未输入源码时,程序输出
Wrong Format - 当没有统计数据时,输出为空
- 当有统计数据时,关键字按照升序排列,每行输出一个关键字及数量,格式为
数量\t关键字
设计与分析
相应类图:

SourceMonitor的生成报表:

源码
import java.util.*;
public class Main {
public static int [] cnt = new int[1000];
public static String []s = {"abstract","assert","boolean","break","byte",
"case","catch","char","class","const","continue","default",
"do","double","else","enum","extends","false","final",
"finally","float","for","goto","if","implements",
"import","instanceof","int","interface","long","native",
"new","null","package","private","protected",
"public","return","short","static","strictfp","super",
"switch","synchronized","this","throw","throws",
"transient","true","try","void","volatile","while","tese"
,"hewe","wdw","wdwd","wdwd","wdwaf","wdwad","wdwdwa"};
public static boolean f=false;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
wd Wd = new wd();
Wd.stop();
for(int i = 0; i < 100; i++)
cnt[i] = 0;
Wd.stop();
String t;
Wd.stop();
while(true) {
Wd.stop();
t=sc.nextLine();
Wd.stop();
int n=t.length();
Wd.stop();
if(t.compareTo("exit") == 0)
break;
Wd.stop();
f=true;
Wd.stop();
for(int i=0;i<n;i++) {
Wd.stop();
String t1="";
Wd.stop();
if(i < n && t.charAt(i) == '"') {
Wd.stop();
i++;
Wd.stop();
while(i < n && t.charAt(i) != '"')
i ++;
Wd.stop();
i++;
Wd.stop();
}
while( i < n && (Character.isLowerCase(t.charAt(i)) || t.charAt(i) == '=') ){
Wd.stop();
t1 += t.charAt(i);
i++;
Wd.stop();
}
if(i < n && t.charAt(i) == '"') {
Wd.stop();
i++;
Wd.stop();
while(i < n && t.charAt(i) != '"')
i++;
}
for(int j=0;j<53;j++) {
if(t1.equals(s[j])) {
cnt[j]++;
// Wd.stop();
break;
}
}
Wd.stop();
if(i < n && t.charAt(i) == '/' && t.charAt(i+1) == '/')
break;
Wd.stop();
if(i < n && t.charAt(i) == '/' && t.charAt(i+1)== '*') {
Wd.stop();
int flag = -1;
Wd.stop();
for(int j = i+2; j < n-1; j++)
if(t.charAt(j) == '*' && t.charAt(j+1) == '/') {
Wd.stop();
flag=j+2;
Wd.stop();
break;
}
String t2 = "";
Wd.stop();
while(flag == -1) {
Wd.stop();
t=sc.nextLine();
Wd.stop();
n=t.length();
Wd.stop();
for(int j = 0; j < n-1;j++)
if(t.charAt(j) == '*'&& t.charAt(j+1) == '/') {
Wd.stop();
flag = j+2;
Wd.stop();
break;
}
Wd.stop();
if(flag != -1)
break;
Wd.stop();
}
Wd.stop();
for(int j = flag; j < n; j++)
t2 += t.charAt(j);
Wd.stop();
t=t2;
Wd.stop();
n=t.length();
Wd.stop();
i=-1;
}
}
}
sc.close();
if(!f)
System.out.println("Wrong Format");
else {
for(int i=0;i<53;i++) {
if(cnt[i]>0)
System.out.printf("%d\t%s\n",cnt[i],s[i]);
}
}
}
}
class wd{
private long j = 0;
public void stop() {
for(int i = 1;i <= 50;i++) {
while(j<1000) j++;
while(j>100) j--;
}
j = Math.abs(j);
j = 0;
}
}
总结
这几次题目集都相较于上一次难度大了许多,也在题目中运用到了很多新学的知识:在创立一个对象后便有明确的功能性,通过继承,多态,接口可以在不同对象上实现不同的功能;对字符串的校验处理上,通过对正则表达式的深入学习,掌握对复杂数据的校验,截取,替换等,作为一项工具使用,在程序复杂度上大大降低。在课堂上,希望老师不仅可以有对知识的讲解,与编程思想的演练,更可以对pta或者实验的难题加以点评与讲解,让作业不会得过且过,而是让我们更为深刻的了解一道题目应该如何去设计。

浙公网安备 33010602011771号