一、前言:
这一阶段的作业已经结束了,较前一次的PTA作业难度上、题量上均有所提升,当然学到的东西也会更多,下面具体讲一讲。
1.题目集04:
本次题目集共三道题:
7-1水文数据校验及处理、7-2 日期问题面向对象设计(聚合一) 、7-3 图形继承
7-1题主要锻炼正则表达式的应用,7-2题为日期类题目与题目集五的7-5题有迭代关系,7-3题主要锻炼继承的知识。
总的来说本次题目集题量小,7-1难度大,7-2与7-3难度适中。
2.题目集05:
本次题目集共五道题:
7-1 找出最长的单词、7-2 合并两个有序数组为新的有序数组、7-3 对整型数据排序、7-4 统计Java程序中关键词的出现次数、7-5 日期问题面向对象设计
7-1十分简单,7-2主要用到Arrays.sort();方法,7-3为三种排序方法:冒泡、选择、插入排序,7-4需要主要锻炼正则表达式的内容,自行了解java中的关键字,7-5为题目集四中7-2的 迭代,主要锻炼的是封装等问题。
总的来说题目集五的难度较题目集四来说难度降低,题量加大。
3.题目集06:
本次题目集共六道题:
7-1 正则表达式训练-QQ号校验、7-2 字符串训练-字符排序、7-3 正则表达式训练-验证码校验 、7-4 正则表达式训练-学号校验 、7-5 图形继承与多态、7-6 实现图形接口及多态性。
其中7-1、7-3、7-4都非常简单锻炼一些简单的正则表达式的知识,7-2也比较简单主要用到了substring()和Arrays.sort()的方法,7-5、7-6锻炼的主要就是多态及接口的知识不难。
总的来说题目集题量大但是难度总体上偏低。
二、设计与分析
1.题目集04 7-2与题目集05 7-5两种日期类聚合设计的优劣比较
以下为7-2类图:
以下为7-5类图:
做这两个题时的过程大体相同,拿到题后先观察题目已给的类图以及题目要求编写代码,首先能看出所有的功能都是在DateUtil类中实现,然后根据DateUtil的方法,具体衍生出Year,Month,Day类,然后具体代码根据题目具体要求编写。
通过对两个类图的比较就可以看出:这两个题都要求类与类之间的关系是聚合关系,并且都是以Day、Month、Year类为实体类,DateUtil为业务类。
7-2中的Day、Month、Year、DateUtil类之间呈现递进式的,但是在在7-5中Day、Month、Year类之间没有聚合,而是Day、Month、Year类与类DateUtil分别聚合。在我看来第二个聚合类与类之间的独立性更强,安全性更高,但是这就导致DateUtil类的任务更重,更繁琐。而第一种聚合的线性关系如果出现了错误可能会导致一系列的错误,让我来选的话我会更喜欢第二种聚合方式。
2.题目集04(7-3)、题目集06(7-5、7-6)三种渐进式图形继承设计的思路与技术运用
①以下为题目集04(7-3)的类图分析(没画main类):
这个题要求在题目指导中说得很清楚,包括对一些对象的封装也说的很清楚:如图示,接下来就是按照题目要求写编写代码。
这个题目中最多就是要求了对对象的封装和类与类之间的继承,以Ciercle类为例,在子类中需要重写的方法就是面积的求法。
class Circle extends Shape{ private double radius = 0; public Circle(double radius) { super(); this.radius = radius; } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } public double getArea() { //求圆的面积 return PI*radius*radius; } }
②.题目集06(7-5)以下为类图及复杂度分析图
根据题目要求写出父类Shape类,getArea()方法为抽象方法,功能为求得图形的面积;validate()方法也为抽象方法,对图形的属 性进行合法性校验;toString()继承自 Object,功能为输出图形的面积信息,但是我在编写的时候没有用题目里要求的toString()方法,而是用allArea,来得到被计算图形面积的总和,然后就是子类中对getArea()方法、validate()方法的重写,及对象的封装。每个子类的方法具体化后,编写Main类,在Main类中实现题目中的“从键盘首先输入三个整型值(例如a b c),分别代表想要创建的Circle、Rectangle及Triangle对象的数量,然后根据图形数量继续输入各对象的属性值(均为实型数),数与数之间可以用一个或多个空格或回车分隔。”,这个题主要要求掌握类的继承、多态性及其使用方法。
③题目集06(7-6)以下为类图及复杂度分析图:
拿到这个题后首先就在Main类中创建了接口GetArea,在该接口中定义了GetArea()的方法,定义新的类继承接口中的方法并将方法重写。这个题我写的代码与题目要求的出入较大。稍后会在踩坑心得中体现。
3.对三次题目集中用到的正则表达式技术的分析总结
当初在网上学习正则的时候就看到这样一句话:正则表达式是繁琐的,但它是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。这句话说的绝对不假,对字符串的一些处理在用了正则表达式后提高了编写代码的速率,就比如说题目集06中7-4 正则表达式训练-学号校验那个题:
我用到正则后的核心代码只有一行就可以判断,但是如果不用正表达就十分繁琐了。正则表达式无疑是强大的
Scanner in = new Scanner(System.in); String a = new String(); a = in.next();
//以下为正则表达式的应用 if(a.matches("[2][0][2][0](([1][1-7])|([6][1])|([8][12]))(([0][1-9])|([1-3][0-9])|[4][0])")) { System.out.println("正确"); } else System.out.println("错误"); in.close();
4.题目集05(7-4):
这个题题目要求统计Java程序中关键词的出现次数,首先我查了java的关键字,遇到的第一个瓶颈是输入的问题,后来用通过循环并以nextLine输入到输入到exit结束,输入完了之后就是用正则查询关键字,但是考虑到注释的情况,因为注释中出现的关键字不用统计,所以先用正则判断注释并将注释删掉是最好的方法,经过查询split()方法可以把一个字符串分割成字符串数组。然后就是关键字的统计了,我发现我根本不知道要怎样才能统计出现次数,后来日期快到了,就放弃了。
三、采坑心得
题目集06(7-5)中要求输出各个图形的面积;排序后的各个图形面积那么怎么把本身就是单独个体的每一个图形,面积连接到一起呢,指导书中提示用到可能会用到ArrayList中的add()方法,定义一个double型的ArrayList,然后运用add()方法,此方法可以将数据存储进去。排序输出面积可以通过Collections.sort()进行,以下为具体代码:
ArrayList<Double> sum = new ArrayList<Double>(); for(int i = 0;i<a;i++) { double radius[] = new double[a]; radius[i] = in.nextDouble(); Circle circle = new Circle(radius[i]); if(circle.validate()==false) { System.out.println("Wrong Format"); System.exit(0); } circle.getArea(); circle.allArea(); sum.add(circle.getArea()); } for(int i = 0;i<b;i++) { double width[] = new double[b]; width[i] = in.nextDouble(); double length[] = new double[b]; length[i] = in.nextDouble(); Rectangle rectangle = new Rectangle(width[i],length[i]); if(rectangle.validate()==false) { System.out.println("Wrong Format"); System.exit(0); } rectangle.getArea(); rectangle.allArea(); sum.add(rectangle.getArea()); } for(int i = 0;i<c;i++) { double[] side1 = new double[c]; double[] side2 = new double[c]; double[] side3 = new double[c]; side1[i] = in.nextDouble(); side2[i] = in.nextDouble(); side3[i] = in.nextDouble(); Triangle triangle = new Triangle(side1[i],side2[i],side3[i]); if(triangle.validate()==false) { System.out.println("Wrong Format"); System.exit(0); } triangle.getArea(); triangle.allArea(); sum.add(triangle.getArea()); } System.out.println("Original area:"); for(double n:sum) { System.out.printf("%.2f ",n); } System.out.printf("\nSum of area:%.2f\n",Shape.allarea); System.out.println("Sorted area:"); Collections.sort(sum); for(double n:sum) { System.out.printf("%.2f ",n); } System.out.printf("\nSum of area:%.2f",Shape.allarea); in.close();
题目集06(7-6)由于读题不认真造成与题目要求差别较大的后果:
题目本身要求设计的类图是这样的:
而我的类图是这样的,差别太大,虽然结果是对的,但是一些要训练的没有练到。
另外就是在看题的时候输出的格式一定要认真和题目要求的对比,不然十分搞人心态,比如在写日期的那个题是就是因为输出的格式里边有一个单词错了,找错找了特别长时间,一定要注意。
四、改进建议
代码的复用性问题:
题目集4(7-2)在DateUtil类中要求求输入日期的前、后n天,以及输入两日期时间之间的时间间隔的方法:
public void getNextNDays(int n) { while(n>0) { day.dayIncrement(); n--; if(day.getMonth().getYear().isLeapYear()) { if(day.getValue()>Leap[day.getMonth().getValue()-1]) { day.resetMin(); day.getMonth().monthIncrement(); if(day.getMonth().getValue()>12) { day.getMonth().resetMin(); day.getMonth().getYear().yearIncrement(); } } } else { if(day.getValue()>notLeap[day.getMonth().getValue()-1]) { day.resetMin(); day.getMonth().monthIncrement(); if(day.getMonth().getValue()>12) { day.getMonth().resetMin(); day.getMonth().getYear().yearIncrement(); } } } } System.out.println(showDates()); } public void getPreviousNDays(int n) { while(n>0) { day.dayReduction(); n--; if(day.getMonth().getYear().isLeapYear()) { if(day.getValue()==0) { day.getMonth().monthReduction(); if(day.getMonth().getValue()==0) { day.getMonth().resetMax(); day.getMonth().getYear().yearReduction(); } day.resetMax(); } } else { if(day.getValue()==0) { day.getMonth().monthReduction(); if(day.getMonth().getValue()==0) { day.getMonth().resetMax(); day.getMonth().getYear().yearReduction(); } day.resetMax(); } } } System.out.println(showDates()); } public int getDaysofDays(DateUtil date){ int sum = 0; while(equalTwoDates(date)==false) { sum++; if(compareDates(date)) { date.day.dayIncrement(); if(date.day.getMonth().getYear().isLeapYear()) { if(date.day.getValue()>Leap[date.day.getMonth().getValue()-1]) { date.day.resetMin(); date.day.getMonth().monthIncrement(); if(date.day.getMonth().getValue()==13) { date.day.getMonth().resetMin(); date.day.getMonth().getYear().yearIncrement(); } }//3 2014 2 14 2020 2 15 } else { if(date.day.getValue()>notLeap[date.day.getMonth().getValue()-1]) { date.day.resetMin(); date.day.getMonth().monthIncrement(); if(date.day.getMonth().getValue()==13) { date.day.getMonth().resetMin(); date.day.getMonth().getYear().yearIncrement(); } } } } if(compareDates(date)==false) { day.dayIncrement(); if(day.getMonth().getYear().isLeapYear()) { if(day.getValue()>Leap[day.getMonth().getValue()-1]) { day.resetMin(); day.getMonth().monthIncrement(); if(day.getMonth().getValue()==13) { day.getMonth().resetMin(); day.getMonth().getYear().yearIncrement(); } } } else { if(day.getValue()>notLeap[day.getMonth().getValue()-1]) { day.resetMin(); day.getMonth().monthIncrement(); if(day.getMonth().getValue()==13) { day.getMonth().resetMin(); day.getMonth().getYear().yearIncrement(); } } } } } return sum; }
在这些方法中有些东西是重复用过多次的,我这样写十分耗时耗力,在后来的题目集题目集05(7-5)中考虑到复用的问题把重复出现用到的东西写成另外一种方法,复用率提高:
public void getNextNDays(long n) { //下n天 while(n>0) { n--; setDayMin(); } System.out.println(showDates()); } public void getPreviousNDays(long n) { //前n天 while(n>0) { n--; setDayMax(); } System.out.println(showDates()); } public int getDaysofDates(DateUtil date) { //日期差 int sum = 0; while(!equalTwoDays(date)) { sum++; if(!compareDates(date)) { date.setDayMin(); } else if(compareDates(date)) { setDayMin(); } } return sum; }
五、总结
1.首先学到的是类与类之间的聚合关系,聚合可以增加复用性,并且聚合的耦合度最低
2.然后就是对面向对象运用到的技术中的继承、多态、接口、封装的学习。
①多态性是对象多种表现形式的体现,在我看来就是父类中的方法在子类继承时得到了覆盖,多态的优点有很多,比如灵活等。
②继承的耦合性是最高的,需要注意的是父类中有的方法子类中一定存在,子类有的方法,父类并没有,最好不要继承,因为不符合多态性
③而接口是抽象方法的集合,通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法,接口无法被实例化,但是可以被实现。但要注意的是一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
④而封装则是为了防止该类的代码和数据被外部类定义的代码随机访问