第二次oo博客

一、前言

  第4次题目集,第一道题主要考察正则表达式的相关运用,难度比较大,第二题考察java面向对象中聚合关系,因为题目中给出了详细类图,所以代码整体结构比较清晰,难度适中。第三题考察类之间继承,同样题目中给出了较为清晰的类的构建结构以及继承关系,所以难度适中。总体上看题量适中,除第一题外较为复杂,其他两题的难度还是可以接受。

  第5次题目集,第一题较为简单考察字符串相应的操作,通过length函数以及简单的循环可以轻松搞定。第二题考察数组相关操作,采用了比较简单的方式——创建一个新的数组进而实现合并,同样比较轻松。第三题,考察冒泡排序,插入排序以及选择排序,在通过参考相应示例了解了算法原理后,发现难度适中。第四题考察正则表达式以及接口的应用,两个都是比较陌生的领域所以相较来说难度非常大。第五题实在习题集四的第二题的基础上进行迭代,考察对聚合关系的理解,因为题目中给出相应类图所以难度适中。总体来看此次题目集题量适中,整体难度适中,个别题难度较大。

  第6次题目集,第一、三、四题都是考察正则表达式的运用,但是考察难度相较以往大幅降低,所以还是比较简单。第二题考察字符与ASCII码值之间的关系,比较简单。第五题,考察类的继承及多态,整体还是偏难,通过查阅了相当一部分的资料后才搞清题目思路,在实现过程中也遇到了很多问题。第六题考察接口以及多态性,难度适中,理解相应概念后还是比较容易实现。总体上此次题量适中,难度也适中。

二、设计与分析(重难点题目)

①题目集4(7-2),以及题目集5(7-5)

  7-2:

  类图:

  

  复杂度:
  

  

  7-5:

  类图:

  

  复杂度:

  

 

 

 

   

  两次作业需求相似代码逻辑基本相同,整体解题思路是按照题目中所给出的类图逐步写出相关的类。类中方法的解决思路如下(仅给出有一定难度代码,简单的不予展示。给出代码以题目集5(7-5)为例):

  1)日期增减:Month类和Day类中的月份或日设为最值的方法是用于对日期进行增减,在对日期进行增时,需要考虑到日期的一般性及特殊性。一般性是增减天数不会出现跨月份甚至是跨年份的情况。特殊性则是要考虑上述情况,需要对日期进行相应判断,例如当日期为12月31号,再增加天数则需将月份和日设为最小值,年份加一,日期减法类似,要考虑到平闰年对2月份天数的影响以及各月天数可能不同的情况。

  2)判断日期是否相同:分别比较两个日期的年月日,看数值是否相等。  

  3)前或后N天:利用循环,进行N次的日期的减或增。注:因为题目集5(7-5)测试点采用了最大整形数,所以在求后N天时进行了一些算法优化。

    前:

      public DateUtil getPreviousNDays(int n) {
        for(int i = 0; i < n; i++) {
          day.dayReduction();
          if(day.getValue() < 1) {
            month.monthReduction();
            if(month.getValue() < 1) {
            year.yearReduction();
            month.resetMax();
            }
            setDayMax();
          }
       }
        return new DateUtil(year.getValue(), month.getValue(), day.getValue());
      }

    后:

      public DateUtil getNextNDays(int n) {
        int year0 = 0; //算法优化
        year0 += n / 146097 * 400;
        n %= 146097;
        year0 += n / 36524 * 100;
        n %= 36524;
        year.setValue(year.getValue() + year0);

        for(int i = 0; i < n; i++) {
          if(year.isLeapYear()) {
            mon_maxnum[1] = 29;
          }else {
            mon_maxnum[1] = 28;
          }
          if(day.getValue() < mon_maxnum[month.getValue() - 1]) {
            day.dayIncrement();
          }
          else {
            setDayMin();
            month.monthIncrement();
            if(month.getValue() > 12) {
            month.resetMin();
            year.yearIncrement();
          }
        }
        }
        return new DateUtil(year.getValue(), month.getValue(), day.getValue());
      }

      

  4)检查日期合法性:先判断年份是否在合法范围内,年份合法的话,再判断是否为闰年,是的话将2月最大天数设为29否则为28,再判断日是否大于等于1且小于当月最大天数。  

    public boolean checkInputValidity() {
      if(year.isLeapYear()) {
        mon_maxnum[1] = 29;
      }else {
        mon_maxnum[1] = 28;
      }
      if(year.validate() && month.validate()) {
        if(1 <= day.getValue() && day.getValue() <= mon_maxnum[month.getValue() - 1]) {
          return true;
        }
      }
      return false;
    }

  5)比较日期(a,b,若a>b返回真):先比较年份如果a>b,则返回真,若a<b则返回假;反之判断月份如果a>b,则返回真,若a<b则返回假;反之判断日,如果a>b,则返回真,反之返回假。 

  6)求两日期间隔:先将二者进行排序(本人习惯前者为较大日期),利用循环,使前者日期每次减少一天直到与前者相等,定义一个整型变量记录循环次数,即为日期间隔。     

    public int getDaysofDates(DateUtil date) {
      int days = 0;
      DateUtil date1 = this; //大
      DateUtil date2 = date; //小
      if(!date1.compareDates(date2)) {
        date1 = date;
        date2 = this;
      }  
      while(!date1.equalTwoDates(date2)) {
        date1.getPreviousNDays(1);
        days++;
      }

      return days;
    }

 

  从复杂度来看,以为主体逻辑非常相似所以两次作业代码复杂度相近。主要是对日期合法性的判断以及对日期进行增减时对日期的判断。

  例如:

    public void monthIncrement() {
      int value0 = getValue();
      if(value0 == 12) {
        year.yearIncrement();
        setValue(1);
      }
      else {

        value0 += 1;
        setValue(value0);
      }
    }

 

  从类图分析,两次作业都是以时间相关操作为基础,通过聚合关系将不同类关联起来。但是两次的耦合度还是差距比较大的,同以DataUtil类为例。

  首先以判断日期合法性的方法checkInputValidity()为例。

  在4.7_2中方法主体为:

  public boolean checkInputValidity() {
    if(day.validate()) {
      return true;
    }
    else {
      return false;
    }
  }

  而在5.7_5中方法主体则为:  

  public boolean checkInputValidity() {
    if(year.isLeapYear()) {
      mon_maxnum[1] = 29;
    }else {
      mon_maxnum[1] = 28;
    }

    if(year.validate() && month.validate()) {
      if(1 <= day.getValue() && day.getValue() <= mon_maxnum[month.getValue() - 1]) {
        return true;
      }
    }
    return false;
  }

  可见二者差距比较明显,显然前者更为简便,后者则需要考虑多种情况。但是很显然前者的耦合度更高,可以参考下面的的代码:

  日类中日期判断:

  

  月类中日期判断:

  

   年类中日期判断:

   

   由此可见在4.7_2中判断日期合法性的方法是通过三个类彼此引用从而实现的,虽然整体逻辑相似但5.7_5中采用直接判断年、月、日的合法性,虽然代码略多,但相较前者耦合性更小。其他方法以此类推,主要差别还是在类间方法的调用关系。同时从代码复杂度来看,12、11,二者相似,基本是用于判断输入数据的合法性。

    

②题目集4(7-3)、题目集6(7-5、7-6)三个题目涉及继承关系及封装、继承、多态、接口等相关操作,难度有所提升。

  7-3:

  类图:

  

    

  复杂度:
  

  

  

  题目集4(7-3)主要考察继承关系,先创建shape类作为父类,包含一个简单的输出和一个返回面积(初始值为0.0)的方法,创建子类Circle、Rectangle继承于Shape类,通过重写父类方法,实现得到面积的方法。整体思路较为清晰,根据题目提示逐步构建相应类,求几何图形的面积及体积可参照过往所学过的数学公式。继承关系可以参考以下代码:

    class Shape{
      //求图形面积
      Shape(){
      System.out.println("Constructing Shape");
      }
      public double getArea() {
        return 0.0;
      }
    }

        

        

  其余类以此类推,实现了代码的复用以及清晰的呈现了类之间的关系,通过类图也是能清晰的观察到这点。从复杂度分析,复杂度为17较高,具体来看主要是用于结合了switch的判断输入的合法性,从最初选择的输入判断到每个选择分别判断输入数据的合法性。

 

  7-5:

  类图:

  

  

  复杂度:

  

  、

  题目集6(7-5)在题目集4(7-3)(以下简称7-3)的基础上进一步考察了Java中的多态,自我感觉难度是三次题目中最大的一个。从类的数目上看相较7-3少了Ball和Box类,需求上也剔除了求体积的功能。在任务书中给出了大致的类图,在7-3继承关系的基础上将Shape类改为抽象类,运用了接口,通过应用ArrayList 进行类对象的存储,同时题目也要求在List对类对象的排序。整体比较抽象(个人逻辑思维还是欠缺)。通过查阅资料以及参考过往代码最终完成Shape类: 

  abstract class Shape{
    static double sum = 0;
    public abstract double getArea();
    public abstract boolean validate();
    public abstract String toString();
    static ArrayList<Double> list0 = new ArrayList<Double>();
    public double sumAllArea() {
      sum += getArea();
      return sum;
    }

  }

  在构建Shape类的时候思考了很久,因为题目中没有明确给出排序、求和两个方法所构建的位置,所以纠结了很久。通过参考之前一道相似类型的题,最终只决定将求和的功能放到Shape中。因为考虑到如果将排序放到Shape中,可能需要没添加一个新的对象就需要排序一次,不如整体进行排序。排序方法(先将List转化为对象数组,后采用冒泡排序法)如下:

  

  Shape []shape = new Shape[list.size()];
  list.toArray(shape);
  for(int i = 0; i < shape.length - 1; i++) {
    for(int j = 0; j < shape.length - i - 1; j ++) {
      if(shape[j].getArea() > shape[j+1].getArea()) {
      Shape shape0;
      shape0 = shape[j];
      shape[j] = shape[j+1];
      shape[j+1] = shape0;
      }
    }
  }

 其他功能通过类图也可以比较容易分析出此处不一 一列举,从代码复杂度来看,22还是比较高的,依旧是归咎于判断输入合法性和循环方面,可能代码在判断合法性逻辑上还存在欠缺吧。此外也进一步提高了代码的复用能力,代码层次及类之间关系也比较清晰。

 

  7-6:

  类图:

  

  

  复杂度:

  

 

  题目集6(7-6)相较于以上两个题目,此次题目难度较易,主要考察接口及多态性,运用interface接口,创建GetArea为一个接口,无属性,只有一个GetArea(求面积)的抽象方法,通过implements实现Circle、Rectangle接口。整体思路较简单,通过简单的数学公式则可得出结果。具体代码如下(仅以Circle为例,Rectangle类以此类推):

    

  interface GetArea {

    public double getArea();

  }


  class Circle implements GetArea{
    private double radius;
    Circle(){

    }
    Circle(double radius){
      this.radius = radius;
    }    
    public double getRadius() {
      return radius;
    }
    public void setRadius(double radius) {
      this.radius = radius;
    }
    @Override
    public double getArea() {
      // TODO Auto-generated method stub
      double area = Math.PI * getRadius() * getRadius();
      return area;
    }

  }

  由类图也可看出类间关系还是比较清晰。从复杂度分析,相较于上两次题目,此次作业功能需求较为简单合法性判断较易 ,复杂度因而较低。

  三次题目总的来看,重点是对Java特色的多态及接口考察,需要对相应操作的深度理解,同时也进一步考察对类进行设计的能力。

 

③三次题目集正则表达式总结:

  从题目集4的水文数据校验及处理(以下简称水文处理)到题目集5中统计Java程序中关键词(以下简称关键词)的出现次数 ,以及题目集6中QQ号校验、验证码校验 、学号校验整体难度呈下降趋势。通过题目集6可以看出,我对简单的正则表达式的运用还是有一定思路及解决能力,但是对于较为复杂的数据判断如水文处理就没有解题思路了。关键词的正则表达也是参考了网上的一些思路。总结发现,首先我的欠缺在于不能对数据进行相应分类,习惯于整体操作。其次,对于正则一些特殊处理语法不熟悉,如split(分割)、replace(替换)等,一方面还是由于对数据处理缺乏经验。归根到底还是做题量不足,没有足够的经验,其实通过题目也能感受到正则表达式在生活中的运用极为广泛,所以在这方面还需要更加努力。

 

④题目集5(7-4)中Java集合框架应用的分析总结:相较于利用数组进行数据的存储,集合类的存储长度和存储对象类型不固定,更适用于java中对象数据的存储,复用性和可操作性更强,同时数据处理的效率也更高。

 

 

三、采坑心得

  1、在题目集6(7-5)中,在最后提交环节在图形数均为0的测试点报错了,通过简单的排查,发现代码当输入为0时确实存在bug——链表无法获取[0-1]位置的数据,解决加入了一个判断链表长度的语句。心得:在提交代码时最好自己先检查一遍是否有简单的逻辑错误,不自信的可以在debug测一下。

  报错信息:

  

  更改后代码片段:

  if(list.size() == 0) {
    x = 0;
  }
  else {
    x = list.get(list.size() - 1).sumAllArea();
  }

  测试正常:

       

  2、同样是在题目集6(7-5)中,题目中给出的不合法判断为:如果图形数量非法(小于0)或图形属性值非法(数值小于0以及三角形三边关系),则输出Wrong Format。但事实上在提交代码的过程中圆属性非法报错了,通过与同学讨论发现正确的判断合法性的方法应为:

  @Override
  public boolean validate() {
    // TODO Auto-generated method stub
    if(getRadius() > 0) {
      return true;
    }
    return false;
  }

  而题目中的要求0应该是合法数据,有点不懂。心得:考虑到误解题目的情况,在报错后可以先检查逻辑错误,无误后仍报错的话,可以尝试修改下判定合法性边界。

 

  3、学号校验的正则表达运用中出现错误,在学好序号的测试点出现报错,分析代码逻辑后发现没有考虑到学号为00的不合法数据。

  原正则匹配代码:(20){2}((1[1-7])|(61)|(7[1-3])|(8[1-2]))(([0-3][0-9])|(40)),利用测试工具可以发现错误。

    

 

  更改后正则匹配代码:(20){2}((1[1-7])|(61)|(7[1-3])|(8[1-2]))(([1-3][0-9])|(40)|(0[1-9])),在最后学号后两位的判断中,在原有基础上添加了判断以零开头的两位数。

  测试结果:

  

  

四、改进建议

  1、在题目集4(7-2)中,没有充分理解题意,导致部分题干中给出的方法没有用到,例如将月份或天数设置为最大或最小。具体方法如下(以月份为例):

    public void resetMin() {
      setValue(1);
    }
    public void resetMax() {
      setValue(12);
    }

 

    月份增减的方法:    

    public void monthIncrement() {
      int value0 = getValue();
      if(value0 == 12) {
        year.yearIncrement();
        setValue(1);
      }
      else {
        value0 += 1;
        setValue(value0);
      }
    }


    public void monthReduction() {
      int value0 = getValue();
      if(value0 == 1) {
        year.yearReduction();
        setValue(12);
      }
      else {
        value0 -= 1;
        setValue(value0);
      }
    }

  很容易看出,将月份设置为最大或最小的方法并没有用上,事实上在例如setValue(12)的位置应替换为resetMax() 方法,日期类中也有同样的欠缺。

  

  2、在进行两个对象数据比较时,可以直接调用对象中get方法获取数据。以题目集4(7-2)为例:
  在判断两个日期相等的方法中,原代码中定义了许多变量来表示相应数据,事实上可以直接采用get的方法,没必要重新定义变量,这样可以使代码更简洁。

  原代码:

  public boolean equalTwoDates(DateUtil date) {
    int year1 = day.month.year.getValue();
    int month1 = day.month.getValue();
    int day1 = day.getValue();
    int year2 = date.day.month.year.getValue();
    int month2 = date.day.month.getValue();
    int day2 = date.day.getValue();
    if(year1 == year2 && month1 == month2 && day1 == day2) {
      return true;
    }
    else {
      return false;
    }
  }

 

五、总结

  1、通过三次题目集的练习,对老大难——正则表达式有了进一步理解,以及能进行简单的应用,同时有了一定的解题经验,比如可以先对数据进行合理分组,分别进行相应操作,进而简化难度。

  2、复习了所学过的一些基本算法比如冒泡排序、选择排序,以及了解了一种新的排序方法——插入排序。

  3、通过练习对java中的多态、抽象类、接口、继承及聚合等有了更深刻的理解,学会如何创建抽象类以及将抽象方法实体化。如何通过子类对父类的继承,进而重写父类方法,实现代码的复用功能。如何利用Map、ArrayList等存储对象数据,并进行相应操作。

  4、对一些相关语法还有欠缺如String中的split、equals、isEmpty、append等相关方法。

  5、对java多态、集合框架的理解还有所欠缺,不能熟练的使用,没有清晰的知识体系。

  5、建议:希望老师在后续的学习过程中,可以将练习版块的难度分解,比如题目集6中的正则表达的考察,从各个较为简单子功能出发,最后实现将子功能集合且有一定难度的题目(例如水文数据处理)。我认为这样可以将降低题目难度的跨度,同时能切实的积累一些经验,再解决难题时会更有思路。

 

  

  

 

posted @ 2021-04-28 15:45  特立独行*  阅读(77)  评论(0)    收藏  举报