第二次博客作业

一、前言:

简要来说,就是这三次作业,个人认为有难度。因为这几次对于类之间的关联又进行了进一步的加强,例如封装、继承、多态,接口等关系,因此要求我们有更强的逻辑推理能力。不仅如此,这几次作业也仍然伴随着正则表达式的踪影,😔,真的是,给我很大的冲击力呀。由于能力问题,本人还是参照网上代码进行修改的,结果就是,查重率有点高呀,所以呢,看来以后还是要攻破正则表达式这一难关。

二、分析:

分析代码工具:SourceMonitor是一款免费的代码度量工具,运行在Windows平台下。它可对多种语言写就的代码进行度量,包括C、C++、C#、Java、VB、Delphi和HTML,并且针对不同的语言,输出不同的代码度量值。像其他代码度量工具一样,SourceMonitor只关注代码,并为编码人员提供及时的反馈,它不是一款项目管理工具,不关注项目实施中从功能分析到设计编码,再到测试这整个过程。

PowerDesigner是一个功能强大而使用简单工具集,提供了一个复杂的交互环境,支持开发生命周期的所有阶段,从处理流程建模到对象和组件的生成。PowerDesigner产生的模型和应用可以不断地增长,适应并随着你的组织的变化而变化。

1、题目集4(7-2)和题目集5(7-5)

参考题目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 //测试两个日期之间相差的天数

题目集4(7-2)的类图及相应的代码度量值:

 

题目集5(7-5)的类图及相应的代码度量值:

 

 

 (1)分析与设计:

从上面的Power Designer和SourceMonitor对这两个代码进行的分析可以看出,题目集5(7-5)的实现代码对这些类之间的联系更浅一点,没有太多关联让类图看起来连接的线太多。而从它们的代码度量值可以看出这两个代码的总体性质是差不多的,但是Max Complexity最大复杂度都超出了最理想的标准。然后从每个方法的分析中可以看到,求两个日期之间的天数public int getdayssofDates(DateUtil date)方法以及求前几天的方法和求后几天的方法的复杂度已经超出了平均复杂度,在所有方法中占大头。也可以看出的就是,题目集4(7-2)的最大深度也超出了理想值,而题目集5(7-5)并没有,这是因为7-2里面,它们的类之间都是通过逐级引用,导致最后的计算类DateUtil里面要一步步地向深层发展,才能找到要使用的与年相关的信息。

(2)踩坑心得:还好吧,因为给了对应的类图,坑还是不多的,主要就是算相差日期真的很令人头疼。

(3)改进建议:

对以上两种不同设计算法的分析,我们可以发现最大问题就是最大复杂度的改进空间很大,因此对于主要的实现三种日期操作的方法还有待改进。而博主呢,已经心力交瘁了,希望看到的同学可以给出建议。

 

 2、题目集4(7-3)、题目集6(7-5、7-6)三种渐进式图形继承设计的思路与技术运用(封装、继承、多态、接口等)

题目集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)设计与分析:

从题目要求以及以上两幅图对实现代码的分析可以看出,这里具有双重继承,平面图形继承自Shape类,立体图形继承自平面图形。分别改写它们的求面积方法,然后再加上相应的所需的求体积的方法,因此这个类图很清晰地表示出了类之间的关系。而对于代码度量值来说,它的基本参数的取值除了最大复杂度Max Complexity未达到理想值以外,其它都还可以。

(2)踩坑心得:

这里的BOX类要求立方体的体积,可以说,我在立方体这几个字这里真的纠结了好几天,一直在想,到底是三棱锥、四棱锥、还是其它的。因为它们的求体积的公式真的有很大区别,所以这个总不能是所有情况都要说明吧。因此,一直卡在这里没有进展。尴尬的是,和同学讨论了一下,发现,好吧,是我想多了,原来就是一个长方体(立方体)呀,我的天,简直有被自己的解读感到心累。

(3)改进建议:

由图可见,要改进的地方只有最大复杂度了,个人认为可以将Shape设为一抽象类或者接口即可降低复杂度,因为抽象的东西和接口在做代码分析时是不在考虑范围内的。可参考以下几种情况。

题目集6(7-5)

getArea()方法为抽象方法,功能为求得图形的面积;validate()方法也为抽象方法,对图形的属 性进行合法性校验。

学习 Java 语言的过程中,对于多态的理解是非常关键的,理解了多态也就意味着打开了理解 Java 各种“抽象”的大门。 所谓的“多态”,简单的理解就是对象在不同情况下的不同表现,具体体现在定义和功能两个方 面,简单的总结一下,多态可以用“三个定义和两个方法”来总结。三个定义分别是父类定义子类构 建、接口定义实现类构建和抽象类定义实体类构建,而两个方法分别是方法重载和方法重写。本次作 业我们采用的是抽象类定义、实体类构建的方式。即 Shape 为抽象类,Circle、Rectangle 及 Triangle 为实体类。

(1)设计与分析:

根据给定的作业指导书,将Shape设为抽象类,里面包含两个抽象方法。对于抽象方法而言,没有对其任何描述,只需定义其名字即可。对于实体类的设置即可通过以下表示

Shape []s=new Circle[a];
        Shape []r=new Rectangle[b];
        Shape []t=new Triangle[c];
abstract class Shape{
    public abstract double getArea();
    public abstract boolean validate();
}

从类图和代码度量值中可以看出,和题目集4(7-3)相比,类图变得更加简洁,而对于最大复杂度的取值也有相应的减小。这就是抽象类和抽象方法与实体父类的区别。

(2)踩坑心得:本人是先看了题目给定的指导书,然后再进行设计的,指导书中说可能要用到Object类的toString()方法,因此我一开始就把这个方法也加在Shape类中了,提交的时候一直显示答案错误,因此拿到编译软件中运行,才发现,这个方法一直报错,于是我就把它删掉了,因为我本来也没用到这个方法,我都是直接写的System.out.println()输出图形的属性及状态的。

(3)改进与建议:自然还是要降低最大复杂度了。

题目集6(7-6)

  • GetArea为一个接口,无属性,只有一个GetArea(求面积)的抽象方法;
  • Circle及Rectangle分别为圆类及矩形类,分别实现GetArea接口
  • 要求:在Main类的主方法中分别定义一个圆类对象及矩形类对象(其属性值由键盘输入),使用接口的引用分别调用圆类对象及矩形类对象的求面积的方法,直接输出两个图形的面积值。(要求只保留两位小数)

(1)设计与分析:

通过Power Designer和SourceMonitor的专业分析,我们可以很明显地发现,通过接口实现的实体类的代码,性功能要比实体父类,抽象父类好。因为类图中,每个类之间的联系又变得更加清晰了,而代码度量值,尤其是一直困扰着我们的最大复杂度明显降低了,其他属性值也越接近于理想值了。

interface GetArea{
    public abstract double getArea();
}

(2)踩坑心得:相对来说比较简单

(3)改进建议:无

(4)总结:

一 接口和抽象类的相似性

1 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。

2 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。

二 接口和抽象类的区别

1 接口里只能包含抽象方法,静态方法和默认方法,不能为普通方法提供方法实现,抽象类则完全可以包含普通方法。

2 接口里只能定义静态常量,不能定义普通成员变量,抽象类里则既可以定义普通成员变量,也可以定义静态常量。

3 接口不能包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

4 接口里不能包含初始化块,但抽象类里完全可以包含初始化块。

5 一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承不足。

 

 3、对三次题目集中用到的正则表达式技术的分析总结

正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑。正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串。

给定一个正则表达式和另一个字符串,我们可以达到如下的目的:

1. 给定的字符串是否符合正则表达式的过滤逻辑(称作"匹配");

2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。

(1)7-1 正则表达式训练-QQ号校验 (5 分)

校验键盘输入的 QQ 号是否合格,判定合格的条件如下:

  • 要求必须是 5-15 位;
  • 0 不能开头;
  • 必须都是数字;
    String str=input.nextLine();
            String s="[1-9][0-9]{4,14}";
            if(str.matches(s))
                System.out.println("你输入的QQ号验证成功");
            else
                System.out.println("你输入的QQ号验证失败");

(2)7-3 正则表达式训练-验证码校验 (5 分)

接受给定的字符串,判断该字符串是否属于验证码。验证码是由四位数字或者字母(包含大小写)组成的字符串。

String s="[a-zA-Z0-9]{4}";

3)7-4 正则表达式训练-学号校验 (7 分)

对软件学院2020级同学学号进行校验,学号共八位,规则如下:

  • 1、2位:入学年份后两位,例如20年
  • 3、4位:学院代码,软件学院代码为20
  • 5位:方向代码,例如1为软件工程,7为物联网
  • 6位:班级序号
  • 7、8位:学号(序号)

要求如下:

  • 只针对2020级
  • 其中软件工程专业班级分别为:202011~17、61,物联网工程专业班级为202071~202073,数据科学与大数据专业班级为202081~82
  • 每个班级学号后两位为01~40
    String s1="2020(1[1-7]|61|7[1-3]|8[1-2])(0[1-9]|[1-3][0-9]|40)";

(4)总结:正则表达式的题目老感觉很难,因为总感觉就是拿着一堆乱码去匹配,然后每次去匹配的标准还不一样,就感觉更难了。但是这几次的还相对来说就是比较基础,从它的分值就看得出来,分都不高。于是,终于尝试了一下自己写,因为书上的附录有一些关于匹配原则的,然后网上也有很丰富的资源,因此虽然磕磕碰碰,也是有成果的,感觉自己终于摸到了一点正则表达式的边边,继续加油喽。

 

4、题目集5(7-4)中Java集合框架应用的分析总结

7-4 统计Java程序中关键词的出现次数 (25 分)

编写程序统计一个输入的Java源码中关键字(区分大小写)出现的次数。说明如下:

  • Java中共有53个关键字(自行百度)

  • 从键盘输入一段源码,统计这段源码中出现的关键字的数量

  • 注释中出现的关键字不用统计

  • 字符串中出现的关键字不用统计

  • 统计出的关键字及数量按照关键字升序进行排序输出

  • 未输入源码则认为输入非法

 

(1)设计与分析:

从以上两个软件的分析结果可以看出,代码只有一个Main类,过于冗余,因此造成了它的Avg Complexity平均复杂度和Max Complexity最大复杂度以及每个方法包含的属性都远超出了理想值。因此这个算法的设计并不好,当然了,因为我也不太会,这题是借鉴其他同学的代码写出来的。

(2)踩坑心得:个人认为,都是坑,因为一开始就来个自行百度java关键字,然后又是输入一段源代码,分别去检测出现的关键字以及出现次数,然后又有说明注释里面还有字符串里面的需要剔除。因此,心有余而力不足不会写。

(3)改进建议:让其更加符合设计规则。

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner input=new Scanner(System.in);
        String a;
        StringBuilder ss=new StringBuilder();
        Map<String, Integer> map=new HashMap<String, Integer>();
        String []key= { "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"
            
        };
       
        int j=0;
        for(int i=0;;i++) {
            a=input.nextLine();
            if(a.equals("exit"))
                break;
            if(a.matches("(.*)//(.*)"))
            {String b[]=a.split("//");
                ss.append(b[0]+" ");
                //ss.append('\n');
                }
            else 
                {ss.append(a+" ");
                //ss.append('\n');
                }
        }
        int count=0;
        String s=ss.toString();
    //    System.out.println(s);
        Pattern p=Pattern.compile("\"(.*?)\"");
        Matcher m=p.matcher(s);
        while(m.find()){
          s=s.replace(m.group()," ");
          p=Pattern.compile("\"(.*?)\"");
          m=p.matcher(s);
        }
      p=Pattern.compile("/\\**(.*?)/");
       m=p.matcher(s);
       while(m.find()){
          s=s.replace(m.group()," ");
         // p=Pattern.compile("/\\*(.*?)\\*/");
          m=p.matcher(s);
       }
       // System.out.println(s);
        if(s.isEmpty())
            {System.out.println("Wrong Format");
            System.exit(0);
            }
         s=s.replace("["," ");
         s=s.replace("]"," ");
        s=s.replace("-","a");
         s=s.replace("*","a");
         s=s.replace("/","a");
         s=s.replace("+","a");
        s=s.replace(">","a");
         s=s.replace("=","a");
        s=s.replace("!","a");
         s=s.replace(":","a");
        s=s.replace("\\","a");
         s= s.replaceAll("[^a-zA-Z]", " ");
         
        String []s1=s.split("[  ' ']");
        for(int i=0;i<s1.length;i++)
        {//System.out.println(s1[i]);
            for( j=0;j<key.length;j++)
            if(s1[i].equals(key[j]))
            {    
                map.put(key[j], 0);
        }
        }
            for( int i = 0;i<s1.length;i++)
            {
                for( j=0;j<key.length;j++)
                if(s1[i].equals(key[j]))
                {    count=map.get(key[j]);
                    map.put(key[j], count+1);
            }
        }
        Set set=map.keySet();
        Object[] arr=set.toArray();
        Arrays.sort(arr);
        for(Object k:arr){
            System.out.println(map.get(k)+"\t"+k);
        }
    }
    String termExpress = "([+-]?[1-9][0-9]*)?" + "(\\*?[+-]?x(\\^([+-]?[1-9][0-9]*))?)?";
    String wholeExpress = "(([+-]?[1-9][0-9]*)?" + "(\\*?[+-]?x(\\^([+-]?[1-9][0-9]*))?)?)+";
    String constNum = "[+-]?[0-9]+";
    public boolean check() {
        CharSequence mp3 = null;
        return Pattern.matches(wholeExpress, mp3);
    }
}

(4)总结:集合主要有Collection和Map接口。

List特点:元素有放入顺序,元素可重复 

Map特点:元素按键值对存储,无放入顺序 

Set特点:元素无放入顺序,元素不可重复(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的) 

List接口有三个实现类:LinkedList,ArrayList,Vector 

LinkedList:底层基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢 

ArrayList和Vector的区别:ArrayList是非线程安全的,效率高;Vector是基于线程安全的,效率低 Set接口有两个实现类:HashSet(底层由HashMap实现),LinkedHashSet SortedSet接口有一个实现类:TreeSet(底层由平衡二叉树实现)

 Query接口有一个实现类:LinkList 

Map接口有三个实现类:HashMap,HashTable,LinkeHashMap   

HashMap非线程安全,高效,支持null;HashTable线程安全,低效,不支持null SortedMap有一个实现类:TreeMap 

其实最主要的是,list是用来处理序列的,而set是用来处理集的。Map是知道的,存储的是键值对 set 一般无序不重复.map kv 结构 list 有序。

 

三、总结:

1、这三次作业让我们离中心的更加规范的java设计又近了一步,学习了继承,抽象父类,抽象方法,接口,以及集合的应用,又进一步的提升了我的编程能力,初步形成了面向对象设计的思想,以及类与类之间的关系都得到了一定程度的掌握,这三次习题集的有一定的收获。

2、对课程的建议

  经过这两个阶段的学习,我们对OOP也有所理解和感悟。但是对于封装性、继承性与多态性的理解还是很抽象,依旧是迷迷糊糊的。希望老师在上课的时候可以继续讲解。老师举例讲课的方法很形象,但是我们需要时间慢慢去体会,对于我这种理解能力不强的,可能会跟不上老师的节奏,而且有的时候因为网络延迟问题听不清老师讲课,所以下课要不断看回放,希望老师能在下课后快一点将回放放出来便于我们再次去学习和理解。同时我注意到实验是没有回放的,希望老师加上。

  对于作业题量我没什么建议,毕竟学习就是需要不断去练习,不断的练习。但是第一次运用新知识总是比较困难的,所以希望新内容考察的题目可以降低一点难度,平时总是有些难以下手不知所措的感觉。PTA题目的指导书很棒,每当我思路空白的时候它总是能给我很多帮助,希望可以详细一点同时对一些 定义内容进行解释,毕竟我们现在没有课本,这会对我们帮助很大的。

 

 

 

 

 

 

 

 

posted @ 2021-11-13 15:19  芥子镯  阅读(91)  评论(0)    收藏  举报