第二次Blog
一、作业总结
这三次题目集较第一次作业难度有进一步提高,考察抽象类、接口等。在写这次作业的同时,不仅要在较短的时间内学习相关知识点,还要会掌握,确实有点难度。题目集4在一次考察对正则表达式的使用,但是相较之前的多项式求导,难度有所降低,但题目复杂程度依然不减。题目集4还考察了继承的用法。题目集5主要依然是考察正则表达式的运用。题目集6旨在掌握类的继承、多态性及其使用方法、使用接口及类实现多态性。
从结果来看,虽然每道题都有认真完成,但有几道题还未能拿到满分。
二、题目分析
下面对三次作业做个简要的分析。
1.日期问题面向对象设计(聚合一)(题目集4)
由于老师在题目上给了类图,所以对于代码的整体有个比较明确的框架思路也非常清晰,有个明确的方向。唯一需要注意的是相关方法里的算法,注意算法是否错误。一开始,由于我的算法上存在一些错误,一直没有办法通过。后来仔细重新看了下题目,由于范围的看错导致浪费了很多不必要的时间。
public void resetMin(){//日期复位
value = 1;
}
public void resetMax(){//日期设为该月最大值
value = mon_maxnum[month.getValue()-1];
}
public void dayIncrement(){//日期增1
value++;
}
public void dayReduction(){//日期减1
value--;
}
public void resetMin(){//月份复位
value = 1;
}
public void resetMax(){//月份设置为12
value = 12;
}
public void monthIncrement(){//月份增1
value++;
}
public void monthReduction(){//月份减1
value--;
}
public void yearIncrement(){//年份增1
value++;
}
public void yearReduction(){//年份减1
value--;
}
对于以上这些方法,我并没有用到,但有一些方法内可以用到,但语句过于长所以我认为用不到。在以后的写题过程中如果没有强制要求,我个人认为其实可以不用特意使用。
另外,在以下代码中
public boolean validate() {
if(this.getMonth().getYear().isLeapYear())
mon_maxnum[1]++;
if(value >= 1 && mon_maxnum[month.getValue()-1] >= value)
return true;
return false;
}
前一次作业中我没有用上这个mon_maxnum[]这个数组,导致代码过于简单且繁多,使用后代码精简了不少,提高了代码的复杂性。
Main类结构:


通过报告中可知,红线处的代码还需要做改良。
2.图形继承(题目集4)
该题旨在实现图形类的继承。使用继承,可以减少代码量,常用方法可以不必定义,直接继承父类定义好了的方法,提高了编程效率,体现了软件的三特性之一的可复用性。掌握了用法后,这道题难度并不大。
class Shape{
public void Shape(){
System.out.println("Constructing Shape");
}
public double getArea()//求图形面积
{
return 0.0;
}
}
class Circle extends Shape{
public void Circle(){
System.out.println("Constructing Circle");
}
private double radious;
public Circle(){
}
public Circle(double radious){
this.radious = radious;
}
public void setRadious(double radious) {
this.radious = radious;
}
public double getRadious() {
return radious;
}
@Override
public double getArea(){
return Math.PI*radious*radious;
}
}
如上代码所示,子类继承父类时,从父类继承的方法前需加上@Override。在java中,@Override注解是用来指定方法重写的,只能修饰方法并且只能用于方法重写,不能修饰其他的元素,它可以强制一个子类必须重写父类方法或者实现接口的方法。并且,@Override的作用是告诉编译器检查这个方法,保证父类要包含一个被该方法重写的方法,否则就会编译错误,这样可以帮助我们避免一些低级错误。一开始,我有忘记在方法前面加@Override注解,后来发现即便是方法编辑错误了,编译器也不会有提示,这时Shape父类的getArea()方法并没有被重写,将会引起程序出现Bug。子类必须说明extends父类。extends:关键字,继承的意思。子类中定义一个与父类同名,返回类型,参数类型均相同的一个方法,称为方法的覆盖。方法的覆盖发生在子类与父类之间。另外,可使用如下说明的super提供对父类的访问。
class Box extends Rectangle{
public void Box(){
System.out.println("Constructing Box");
}
double height;
public Box(){
}
public Box(double heiget){
this.height = heiget;
}
public void setHeight(double height) {
this.height = height;
}
public double getHeight() {
return height;
}
@Override
public double getArea(){
double length0 = getLength();
double width0 = getWidth();
return length0*width0*2+length0*height*2+width0*height*2;
}
public double getVolume()//求立方体体积
{
return super.getArea()*height;
}
}
最后一个方法中的语句return super.getArea()*height;是使用了父类Rectangle的方法。在java中super代表父类存储空间的标识(可以理解为父类引用可以操作父类的成员)。在这里要和this区分开来。
this:
(1)属性访问:访问本类中的属性,如果本类中没有此属性,则从父类中继续查找。
(2)方法:访问本类中的方法,如果本类中没有此方法,则从父类中继续查找。
(3)调用构造:调用本类构造,必须放在构造方法的首行。
(4)首行:表示当前对象。
super:
(1)属性访问:访问父类中的属性。
(2)方法:直接访问父类中的方法。
(3)调用构造:调用父类构造,必须放在子类构造方法的首行。
用法:
this.成员变量:调用本类的成员变量。而super.成员变量:调用父类的成员变量。
示例:
super可以用来直接引用父类的实例变量。eg:super.name;
super可以用来直接调用父类的方法。eg.super.get();
super()可以用于直接调用父类构造的函数。eg:super();
super和this的区别:
(1)代表的实物不同:
super代表的是父类空间的引用。
this代表的是所属函数的调用者对象。
(2)使用前提不同:
super必须要有继承关系才能使用。
this不需要继承关系也能使用。
(3)调用的构造函数不同:
super:调用父类的构造函数。
this:调用所属类的构造函数。
Main类结构:

3.统计JAVA程序中关键词的出现次数(题目集5)
这道题不仅考察正则表达式的运用,还考察对List、Set、Map的使用。
对于这道题树立正确的思路非常重要。以下是我的大致思路:
(1)使用final声明是关键字数组,可以保证数组内的元素在使用中不被改变。
(2)说明与初始化(使用HashMap用于保存关键字与出现次数,例如:<key,value> = <”int”,3>)。
(3)关键字筛查:读取输入文本的某一行,将该行split为字符串数组,逐个判断是否为关键字,但是首先需要去除非字母和数字字符的影响。
(4)处理注释:读取文本中的每一行,首先判断是否属于注释,若属于则跳过,则不属于则进行关键字筛查。
代码参考如下:
public void countKeyWords(File file) throws IOException {
BufferedReader input = new BufferedReader(new FileReader(file));
String line = null;
while ((line = input.readLine()) != null) {
line = line.trim();
if (line.startsWith("//")) continue; //不处理单行注释
else if (line.contains("/*")) { //多行,文档与尾行注释
if (!line.startsWith("/*")) matchKeywords(line);//第一行算代码,其余算注释
while (!line.endsWith("*/")) {
line = input.readLine().trim();
}
}
matchKeywords(line); //对代码行进行统计
}
}
(4)输出结果。
小结:
写这道题之前,重新又温习了一遍正则表达式的网课,所以在正则表达式上没有大的问题,并且,在每次写正则表达式的时候,我都会使用正则表达式测试网站验证自己的正则表达式,效率和正确率都有所提高。
4.日期问题面向对象设计(聚合二)(题目集5)
聚合二相较聚合一,PTA通过标准更加严苛。代码长度限制有所缩短,提交代码时,代码如果有使用了两个if嵌套,运行大多会超时,那个测试点会不通过。其中有个下n天的测试点我一直没能通过,将N1的类型由int改为long就可以通过。
case 1:
int year1 = Integer.parseInt(in.next());
int month1 = Integer.parseInt(in.next());
int day1 = Integer.parseInt(in.next());
long N1 = in.nextInt();
DateUtil day01 = new DateUtil(year1, month1, day1);
if (!day01.checkInputValidity()) {
System.out.println("Wrong Format");
} else
System.out.println(year1 + "-" + month1 + "-" + day1 + " next " + N1 + " days is:" + day01.getNextNDays(N1).showDate());
break;
Main类结构:

5.图形继承与多态(题目集6)
这道题考察点主要在于深入理解继承与多态的原理及用法还有ArrayList,List等的使用。
为不同的图形创建不同的类,在类中创建计算面积的方法。并将每个图形的面积存入list数组中,一系列输出后。因为list是ArrayList型的,所以可以使用Collection
工具类将其进行排序:Collections.sort(list);
for(double o:list)
System.out.print(String.format("%.2f",o)+" ");
再将list集合遍历赋值给o并输出。
Shape被定义为抽象类,声明为abstract成员可以不包括实现代码,但只要类中还有未实现的抽象成员(抽象方法),那么这个类就是一个抽象类,抽象类的对象不能被实例化,通常作为被强制继承类必须实现某一成员,抽象类必须要有派生子类。并且,如果子类没有实现抽象类的所有方法,则子类也成为一个抽象类。
作为修饰符,abstract声明了一种没有具体对象的,出于组织概念的层次关系需要而存在的抽象类;作为类方法修饰符,abstract则声明了一种仅有方法头,而没有具体操作实现的方法体的抽象方法。
eg.
abstract class Shape{
public abstract double getArea();
public abstract boolean validate();
public abstract String toString();
}
可见,abstract方法只有方法头的声明,而用一个分号代替方法体的定义;至于方法体的具体实现。那是由当前类的不同子类在他们各自的类定义中完成的。
Main类结构:

6.实现图形接口及多态性(题目集6)
这道题考察的是最近学习的实现类的封装性、继承性和多态性。
这是第一次,比较正式的使用接口来写代码。
我在做题后再一次详细整理了接口的一些使用,如下:
(1)声明格式:
使用interface修饰,是一种引用数据类型。
eg.
[访问修饰符] interface接口名 [extends 父接口1,父接口2...]{
常量定义;
方法定义;
}
(2)定义接口说明:
如果一个类中所有的方法均为abstract方法,那么这个类就可以声明为接口。
eg.
源码:
public abstract class MyAbstract{
public abstract void method01();
public abstract void method02();
public abstract void method03();
}
改正后:
public interface MyInterface{
//方法:public abstract void method01();//public abstract可以省略
void method01;
void method02;
void method03;
}
①常量:接口中的属性只能是常量,总是:public static final修饰。不写也是。
②方法:接口中的方法只能是:publci abstract。省略的话,也是public abstract。
③接口不能实例化:接口中不允许出现构造方法。因为接口不是类。
④新特性:使用static来定义静态方法,使用default来定义普通方法。
⑤接口的继承性(传递性):接口完全支持多继承。和类的继承类似,子接口扩展某个父接口,将会获得父接口中所定义的一切。
(3)接口与类的关系:
①子类通过implements来实现接口中的规范。
②一个类既存在继承关系,又存在实现关系时:extends在前,implements在后。
③如果父类与接口有完全相同的方法,子类/实现类所实现的方法是父类的方法(父类优先于接口)。
④如果父类中与接口中有同名方法时,父类与接口中的方法,在子类/实现类中构成方法的重载。
⑤一个类可以同时实现多个接口。
该题使用了接口的部分代码如下:
class Circle implements GetArea{
private double radius;
public Circle(){}
public 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;
}
}
class Rectangle implements GetArea{
private double width;
private double length;
public Rectangle(){}
public Rectangle(double width,double length){
this.width = width;
this.length = length;
}
public void setWidth(double width) {
this.width = width;
}
public double getWidth() {
return width;
}
public void setLength(double length) {
this.length = length;
}
public double getLength() {
return length;
}
public double getArea(){
return width * length;
}
}
Main类结构:

三、总结与心得
1.目前好像只是接触了类设计的单一原则,对该原则的理解是不能跑题,方法必须围绕着类进行。取类名要做到见名知义,属性是分量。
2.通过测试,能够检测编码的质量好坏。
3.明确知晓了类设计的额单一职责原则:类里面的变量的属性一般为私有属性。
4.了解了类和类的四种关系:耦合(关联,聚合,依赖,泛化)且耦合度要越低越好,内聚等的概念;类的封装性:private,public,protected,默认的(都可以不写);类的继承性:可复用性(父类parent class,超类super class,基类base class,子类son class,派生类derived class,及构造方法链的知识点);类的多态性:不同的对象,接收到同一个消息的时候,执行不同的操作。
5.语法依旧还不熟练,导致很多时候在写代码的时候因为某些语法问题卡住或者报错。
6.依然保持着做题前,简单的画一个大致思路的草图,在思路上有明确的方向,只是有很多知识点依然不会,所以就算思路有,很多时候却不好实现。