Blog作业总结02

 

 一、 前言

  OOP的这三次大作业的题目概述如下:

    PTA题目集4:1.水文数据校验及处理;2.日期问题面向对象设计(聚合一);3.图形继承

  题目集4作为第二阶段的开篇,题量虽少难度却不小,其中水文数据校验和处理时这个阶段难度的上限。其中知识点覆盖到正则表达式的运用,以及实体类,业务类的运用,例如StringBuilder类的使用和实践,大量 需要自学的知识。日期问题则是对上阶段应用日期类的提升和拔高,运用聚合的思想,将代码效率最大化,图形继承则是对于父类子类的简单入门运用。

  PTA题目集5:1日期问题面向对象设计(聚合二);2.统计Java程序中关键词的出现次数;3.合并两个有 序数组为新的有序数组;4.对整型数据排序;

   题目集5的题量也比较适中,题目难度略微下降,3、4题是对所学基本知识的复习考查,第2题则是对正则表达式的在此升级运用,难度就直线上升,跨度太大,既要提取出Java源码中的关键字,还要统计出现次数并按照关键字升序进行排序输出,其中还要需要自学List,map,set等接口的使用方法。第1道题则是基于题目集4的聚合方式的改变,以下会讨论两次不同聚合的不同效果。第3题是对以前知识的复习,排序的算法(比如说冒泡排序,选择排序等)

  PTA题目集6:1.正则表达式训练-QQ号校验;2.字符串训练-字符排序;3.正则表达式训练-验证码校验;4.正则表达式训练-学号校验;5.图形继承与多态;6.实现图形接口及多态性;

  题目集6题量是增加了的,但是前面4道题是考察我们对基本正则表达式的掌握与运用,先将基础打牢。后续的第5题是对题目集4图像继承的升级运用,以多态的思想基础进行编程。第6题是对接口的学习和使用做了入门引导,需要进行接口的自学,以实现图形的多态性。

二、 设计与分析

    ①题目集4(7-2)、题目集5(7-5)两种日期类聚合设计的优劣比较 

题目集4当中的7-2类图如下:

 自己所编写的代码在SourceMonitor当中显示的报表结果如下:

  题目集4的7-2为前几次日期类题目的升级迭代,前几次无非运用简单的方法与类的构建处理即可,这一次则是要运用聚合的思想。聚合的概念为:如果一个类有一个类的实体引用(类中的类),则它称为聚合。 聚合表示HAS-A关系。由前几次的日期类题目操作而言,题目功能方法是需要重复调用的,而聚合也恰好符合的更好的对代码的复用。该题目通过构建DateUtil类对处理结果进行集成处理,再由此衍生出Year类,Month类,Day类,进行不同的处理,共同处理包括验证合法性,以及对于日期增减的操作。该题目复杂度较第一阶段这类题型大大降低,体验出了代码复用性的高效率。其中该题目给出了设计类图,基本框架建立后,只需要明白聚合关系的代码编写语法,则可以流畅的完成题目。其中当其他类完成构建后,主类的书写则非常顺畅,开始体现出面向对象编程的一点影子,需要我们去灵活运用。

题目集5当中的7-5类图如下:

 

自己所编写的代码在SourceMonitor当中的所生成的报表结果如下:

  题目集5的7-5较题目集4的日期类题目,虽都同为聚合类型,但聚合的方式不同,该题目的聚合方式类似我对上题分析的改进的模式。其中大体聚合方式便是分开独立处理年,月,日,最后集成于DateUtil完成是输出结果的集成效果。本题目设计的框架:通过将所需的不同功能的分门别类,在主函数通过switch语句引导,进行不同功能的对象的创建。不同的功能统筹在DateUtil类中进行详细划分:闰年判定,前N天,后N天,相差天数等,其中DateUtil类仍是一种大体功能类,大多数详细的小步处理,是通过Year类,Month类,Day类进行详细处理。其中不同于题目集4的日期类题目,这次的聚合不再是连锁性聚合,而是年月日聚合于DateUtil上,互不关联,最终在DateUtil上完成统筹处理,相当于DateUtil为中心工厂,按需向Year,Month,Day中调用所需要的方法。设计有所缺陷在于,没有完全去调用到小类中的方法,更多的处理依旧堆积在DateUtil中。在复杂度平持于题目集4,实际代码书写却更加简洁可观,是一次升级的聚合。

 优劣比较:题目集4:7-2 日期问题面向对象设计(聚合一)&& 题目集5:7-4 日期问题面向对象设计(聚合二)

 聚合一:题目集4中的聚合聚合点在于DataUtil与后续的Year,Month,Day类的结构,并不算完全的聚合形式。其中对于数据的处理更为严谨。若算法不存在问题,则得到的结果基本上不存在差错。该聚合是属于类间的多次聚合,在Day类中用Month定义month,在Month类中用Year定义year等,这样在DateUtil中调用时要跨过多层调用,增加了出错率,而且效率也变低了反之代码可读性大大降低,以及代码操作不方便,代码冗长,为了调用到指定的属性,例如年,还需要分别调用到日,月,再能调用到年。在DateUtil类方法中代码亢长,过于累赘,操作性上不方便,甚至不利于后期修改。

 

聚合二:作为第二次聚合,聚合中心是DateUtil类,该类连结着Year类,Month类,Day类,其中数据处理类似于年月日独立处理,初始结果集成在DateUtil类中,最终得到最后的输出结果,代码操作更为直接可观。如果需要调用什么属性就调用什么属性,不需要走一个固定相同的路线,即调用属性不需要被其他属性限制。作为代码的书写者自然更偏向于聚合二的写法,相对而言作为代码阅读者的话,也更想看到聚合二的写法。以下呈现不同聚合方式在相同方法下的代码写法,直观比较二者。

 

在代码复用性上:聚合一虽然降低了代码的复用性,但在类中多次调用方法需要走多少次相同的路的路向。而在聚合二中,DateUtil依旧是一个做统筹计算与合法的方法。其中聚合二中DateUtil类似于一个中心,当处理数据的方法需要一个特定的方法验证,则可以自己从Year,Month,Day中进行调用。因为聚合二中Year,Month,Day是与DateUtil直接相关,则调用起来非常的方便,直接了当。复用性而言,本题类似于天数的+1,-1是一个需要循环调用的方法,采用聚合二的聚合方式,则可以大大提高代码的复用性,便是不必要多余的代码,用统筹的代码做更多的事。合成/聚合复用原则是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的。

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

  这三道题都是继承类题目,题目集4的7-3是要求我们求面积,几何体的表面积和体积,这道题的目的应该是让我们做了之后,更加熟练的运用Java中的继承这一大特点。继承主要继承父类的属性和方法,在设计父类的时候找所有类相同的属性和方法作为父类的属性和方法,如果子类需要重写该方法直接

@Override 

重写该方法,还需其他属性的话,在super()后再继续添加属性,这能使代码更加简便,思路更清楚;具体设计思路在每题中在下面详细说明。

    题目集4(7-3):主要的设计思路是父类子类的构建,通过在父类中写出主要的功能方法代码,再在各个子类中复写出同名的方法,给予不同的计算形式。通过主类中new出不同的对象,该对象找到对应的类方法,完成所需输出的计算。其中关联到主类中输入的数据如何调用到构造方法,通过调用构造方法,进而调用得到类似求面积,求体积的方法。其中需要自学:父类子类的构建,String.format保留小数的方法,重写方法,以及父类子类对应到主类的构造方法调用。题目主要进行了继承和封装,但是继承的并不是同一个类,因为图形间的联系不一样,Rectangle和Circle是基础图形,继承Shape,求面积以及输出“Constructing Shape”,Ball和Box与Circle和Rectangle相关,所以继承,而且输出的Constructing能明显体现继承间的关系。该题难度不大,思路清晰,按题目要求进行封装和继承即可。而且程序的复杂度不算特别大,除了类间的继承,主要就是主函数的switch-case语句,基本没其他无用的东西,所需的工作量并不大,主要在熟悉继承的规则后,只用完成功能方法的编写,就可以快速的完成主类方法的补充,进而完成题目

 

 题目集6 7-5:键盘首先输入三个整型值(例如a b c,分别代表想要创建的CircleRectangleTriangle的数量,运用了抽象类、继承、封装和ArrayList接口的知识点,以抽象类Shape为父类,其他子类均继承于它,在子类中重写父类的方法。要求我们求图形的面积,根据图形面积对图形对象进行排序并输出,第二题,这道题采用了抽象类定义,实体类构建的一个方式,我们首先有一个Shape类,但这个类与上一题不同的是,这是一个抽象类,拥有抽象的方法,求面积和数据校验,然后它有三个子类分别是,circle类rectangle类和triangle类分别,三个类继承于shape类,重写了求面积和数据校验的方法,我在主函数中分别创建三个类的对象然后将他们放入shape类型的list中,求面积的时候直接调用shape的getArea的方法就可以了,然后再根据面积对list中的对象排序,最后再输出面积。我认为这道题主要是想让我们更深刻的理解继承以及去理解多态,我们求面积只需要调用shape的求面积方法,就可以直接求面积,不需要调用谁谁的求面积去求谁谁的面积,这样的话,可以减少一个建立对象的次数,如果建立对象太多的话,那么使用多态可以避免这种现象的发生,与此同时,我们也可以减少内存的使用,这就是多态的好处,继承和多态提高了代码的可维护性和可延展性。

                                 

 题目集6 7-6:本题通过设计一个程序,通过继承性,封装性以及多态性完成输入对应属性求面积的功能。其中封装性体现在Circle类以及Rectangle类中私有属性的创建。与前两个不同之处便是使用接口来实现了,首先我们创建了一个求面积的接口,接口中有一个求面积的的方法,然后创建了俩个类circle类和rectangle类,这两个类都与接口相连接,这两个类中都有求面积的方法,然后我们在主函数中创建两个对象,声明类型为接口,实际类型还是circle和rectangle,然后调用接口求面积的方法就可以求出面积。这道题主要的目的应该是想让我们了解接口并实践运用它,然后用接口以及类实现多态。通过定义了一个接口,使得所有符合接口接入特性的类都可调用到接口中的抽象方法---求面积,进而调用出实体方法。java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。在不同子类中,完成实现方法的代码内容。

                          

知识点集合:

1)封装:每个类的属性均设置为私有的,再通过公共的(public)方法:getxxx()和setxxx()实现对该属性的操作,这样通过隐藏对象的属性来保护对象内部的状态,提高代码的可用性和可维护性;

例如:题目集4 7-3将矩形的长,宽设置为私有的,通过get,set获取

class Rectangle extends Shape{
    private double length;
    private double width;
    public double getLength() {
        return length;
    }
    public void setLength(double length) {
        this.length = length;
    }
    public double getWidth() {
        return width;
    }
    public void setWidth(double width) {
        this.width = width;
    }
}

(2)继承:通过extend关键字或implements关键字让类与类之间产生继承的关系,super关键字来实现对父类成员的访问,用来引用当前对象的父类,this关键字指向自己的引用。子类可以接受父类非私有属性以及方法,子类就不会存在重复的代码,维护性也提高,代码也更加简洁,提高代码的复用性,继承的出现让类与类之间产生了子父类关系,提供了多态度前提条件;

例如:题目集4 7-3重写分类算面积的方法

@Override
    public double getArea() {
        return Math.PI*radius*radius;
    }

(3)多态:使用多态的一个很重要的前提是使用了继承,然后重写方法,使用多态方法调用时之前必须保证父类中有该方法,可以对所有类的对象做通用处理;可以消除类型之间的耦合关系,增强可替换性,可扩充性,接口性,灵活性,简化性,可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

abstract class Shape{
    public abstract double getArea();
    public abstract boolean validate();
    public abstract String toString();
}
class Circle extends Shape{
    ………………
    @Override
    public double getArea() {
        return Math.PI * getRadius() * getRadius();
    }

    @Override
    public boolean validate() {
        if(radius>0)
            return true;
        return false;
    }

    @Override
    public String toString() {
        return "Circle{" +
                "radius=" + radius +
                '}';
    }
}

(4)接口:Interface关键字用来声明一个接口,在类声明中,Implements关键字放在class声明后面。

例如:题目集6 7-6,用interface关键字声明GetArea的接口。

接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。

class Circle implements GetArea{
    private double radius;

    public Circle(){}
    public Circle(double radius){
        this.setRadious(radius);
    }
    public double getRadious() {
        return radius;
    }

    public void setRadious(double radious) {
        this.radius = radious;
    }

    @Override
    public double getArea() {
        return getRadious()*getRadious()*Math.PI;
    }
}
③正则表达式技术的分析总结
题目集4 7-1 水文数据校检及处理
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,9999],“月”与“日”为一位数时之前不加“0”,日期与时间之间有一个空格,“时”与“分”之间采用冒号分隔(英文半角),“时”为一位数时之前不加“0”,“分”始终保持两位,且始终为“00”。注意:“时”数必须是24小时进制中的偶数值。

 2.目标水位、实际水位、流量格式检验:

"([1-9][0-9]{0,2}(\\.[0-9]{1,3})?)"

格式均为实型数,取值范围为[1,1000), 小数点后保留1-3位小数或无小数(也无小数点)

 3.目标开度、实际开度格式检验:

 对开度进行检验,实型数,取值范围为[1,10),必须保留两位小数,两个开度之间用"/"分隔

"([1-9]\\.[0-9]{2})"

 4.对数据的合法性检验,各个数据之间用“|”符号进行分隔

"(.*)\\|(.*)\\|(.*)\\|(.*)\\|(.*)"

题目集5(7-4)统计Java程序中关键词的出现次数 

 匹配一种注释符,匹配到即将里面的内容去掉,因为注释部分不算关键字

   匹配代码中//:

Pattern p1 = Pattern.compile(".*?(//.*)");

   匹配代码中/* */

Pattern p2 = Pattern.compile(".*?(/\\*.*?\\*/).*?");

   匹配代码中“”

Pattern p3 = Pattern.compile("(\".*?\")");

题目集6(7-1)QQ号校验 

 对QQ号进行校验,要求必须是 5-15 位;0 不能开头;必须都是数字,1-9开头,中间4位到14位可以是0-9

qq.matches("[1-9]\\d{4,14}")

题目集6(7-3)验证码校验

  对验证码进行检验,由四位数字或者字母(包含大小写)组成的字符串

if(s.matches("[a-zA-Z0-9]{4}"))

题目集6(7-4)学号校验

      对20级学生学号进行检验,学号共八位,要求:

  • 1、2位:入学年份后两位,例如20年
  • 3、4位:学院代码,软件学院代码为20
  • 5位:方向代码,例如1为软件工程,7为物联网
  • 6位:班级序号
  • 7、8位:学号(序号)
s.matches("2020(1[1-7]|61|7[1-3]|8[12])(0[1-9]|[1-3][0-9]|40)")

  前四位为2020(软件学院),1方向1-7或者61或者7方向1-3或者8方向1-2(班级),学号1-9的为01-09,然后1或2或3再加任意一个数字(11-39),再然后还有一个40。

总结正则表达式的用法:

\ :将下一字符标记为特殊字符、文本、反向引用或八进制转义符,例如:"n"匹配字符"n"。"\n"匹配换行符。序列"\\"匹配"\","\("匹配"("。

\w:匹配任何字类字符(字母,数字,下划线)与“[A-Za-z0-9_]”等效。

\\\\:表示普通反斜杠。

^: 匹配输入字符串开始位置

$:匹配输入字符串结尾的位置。

*:零次或多次匹配前面的字符或子表达式。

+:一次或多次匹配前面的字符或子表达式,等效于{1,}。

?:零次或一次匹配前面的字符或子表达式,等效于{0,1}。

{n}:n 是非负整数,正好匹配 n 次。

{n,}:n 是非负整数,至少匹配 n 次。

{n,m}:m 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。

[a-z]:匹配指定范围内的任何字符。例如:

"[a-z]"

匹配“a”到“z”范围内的任何小写字母。

[^a-z]:匹配不在指定范围内的任何字符。例如:

"[^a-z]"

匹配“a”到“z”范围内的任何小写字母。

\d:数字字符匹配,等效于

[0-9]

\D:非数字字符匹配,等效于

[^0-9]

  总的来说,正则表达式可以使我们的代码简单,我们用起来非常的方便,如果没有正则表达式,我们可能要用更加复杂的算法去写,去判断一个一个的点是否满足字符串的要求,所以正则表达式是帮助我们去操作字符串的一个好的工具。

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

   该题需要对一段代码统计出的关键字及数量按照关键字升序进行排序输出。在这道题需要我们使用正则表达式进行对注释内容的判断,最后将它们替换成空字符,最后只剩代码
内容进行统计即可。

自己所编写的代码在SourceMonitor当中的所生成的报表结果如下:

//将53个关键字存储到一维数组当中
          //每7个关键字为一行
 String []keyWord= { "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类型的数组,和keyWord的关键字一一对应,并对应它的数量
        //默认它们初始化值为零
        int[] keyWordNumber = new int[53];
        while(true)
        {
            //按行来输入源码的字符串
            sourceCode1 = input.nextLine();
            //如果输入的是exit,那么跳出这个输入循环
            if(sourceCode1.equals("exit"))
                break;
//去除单行注释的情况
            //如果输入的这行源码字符串匹配到了“//”,那么筛选//前面的内容并将其存储到sourceCodeResult里面
            if(sourceCode1.matches(".*//.*"))
            {
                String tempTwo[]=sourceCode1.split("//");
                sourceCodeRecult.append(tempTwo[0]+" ");
            }
            //如果没有“//”,那么直接将这行的源码字符串存储到sourceCodeResult里面即可
            else
            {
                sourceCodeRecult.append(sourceCode1+" ");
            }
        }
//将sourceCode2转换成String类型
        String sourceCode2 = sourceCodeRecult.toString();
        //创建Pattern类下的一个实例
        Pattern p=Pattern.compile("/\\*[^*]*\\*/");//这个是多行注释//创建Matcher类下的一个m
        Matcher m=p.matcher(sourceCode2);
        //调用Matcher类下的一个find方法
        //通过这个方法查找sourceCode2当中有没有这个多行注释
        while(m.find())
        {
            //将多行注释里面的那部分全部替换成空格字符串的形式
            sourceCode2=sourceCode2.replace(m.group()," ");
            m=p.matcher(sourceCode2);
        }
        Pattern q=Pattern.compile("/\\*\\*[^/]*/");//这个是文档注释
        m=q.matcher(sourceCode2);
        //同样的道理,是查找有没有这个文档的注释
        while(m.find())
        {
           sourceCode2=sourceCode2.replace(m.group()," ");
           m=q.matcher(sourceCode2);
        }
        //以下是去除源码当中的字符串内容//如果去除掉以上的这些情况之后,源码为空的话,是以下这样的情况并直接输出
        if(sourceCode2.isEmpty())
        {
            System.out.println("Wrong Format");
            System.exit(0);
        }
 //将除去大小写字母的所有字符串替换成空字符串
        sourceCode2=sourceCode2.replaceAll("[^a-zA-Z]", " ");
        int count=0;
        Map<String, Integer> map=new HashMap<String, Integer>();
        String []string1=sourceCode2.split("[  ' ']");
        for(int i=0;i<string1.length;i++)
        {
            for(int j=0;j<keyWord.length;j++)
                if(string1[i].equals(keyWord[j]))
                {
                    map.put(keyWord[j], 0);
                }
        }

该题目首先通过正则表达式对干扰的符号进行清除替换,以上正则表达式的运用到检测指定字符之后,指定字符之间,指定字符的语法规则。其中通过检测到后替换为空格,剩下有效信息后,进行关键字检索。运用字符串处理后的字符内容仅仅存在可被识别的一个个英文单词,此刻运用hashmap进行检索匹配。

HashMap:它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记录的值为null。

将java关键字都储存于数组,将数组放于hashmap中,通过对hashmap遍历的运用,可以对剩余的有效内容进行检索,完成标记与最终输出。

三、踩坑心得

题目集4:7-2   日期问题面向对象设计(聚合一)

public boolean compareDates(DateUtil date){//比较两个日期大小
        if (date.getDay().getMonth().getYear().getYearValue()<this.getDay().getMonth().getYear().getYearValue())
            return true;
        else if (date.getDay().getMonth().getYear().getYearValue()==this.getDay().getMonth().getYear().getYearValue()
                &&date.getDay().getMonth().getMonthValue()<this.getDay().getMonth().getMonthValue())
            return true;
        else if(date.getDay().getMonth().getYear().getYearValue()==this.getDay().getMonth().getYear().getYearValue()
                &&date.getDay().getMonth().getMonthValue()==this.getDay().getMonth().getMonthValue()
                &&date.getDay().getDayValue()<this.getDay().getDayValue())
            return true;
        return false;
    }

  以该题目中,验证两日期是否相同的主类调用方法为例子,其中对于年月日的调用,若代码语法不符合以上代码的例子,则会出现报错,或者无法真正完成年月日的正确处理与正确校验。其中,再编写该题目之初,未熟悉聚合的语法规则,导致对于年月日的处理方法与校验方法,都未采用类似date.getDay().getMonth().getYear().getValue()这样的写法,写法都只是用直接的year,month,day进行处理,导致代码运行后,得不到结果而且会出现报错。后及时了解写法后,发现需要这样进行处理,则进行的及时订正。采用后在计算算法正确的前提下,可以得到题目所需的正确结果。

存在的问题:在计算两个日期之间的天数差时,得到的结果一直都与正确答案相差1天,在闰年判断的时候因为if-else没有判断对,导致得不到正确答案,改进后的代码:

public int getDaysofDays(DateUtil date){
        int sum=0,i,sum1=0,sum2=0,total=0;
        for ( i = 1; i < date.getDay().getMonth().getYear().getYearValue(); i++) {
            if(date.getDay().getMonth().getYear().isLeapYear(i))
            {sum=sum+366;}
            else
            {sum=sum+365;}
        }
        for(i=1;i<=date.getDay().getMonth().getMonthValue()-1;i++)
        {
            if((i%2==1&&i<=7)||i==8||i==10||i==12){sum1=sum1+31;}
            else if(i==4||i==6||i==9||i==11){sum1=sum1+30;}
            else if(i==2&&!(date.getDay().getMonth().getYear().isLeapYear(i))){
                sum1=sum1+28;
            }else if(i==2&&date.getDay().getMonth().getYear().isLeapYear(i)){
                sum1=sum1+29;
            }
        }
        sum2=date.getDay().getDayValue();
        total=sum+sum1+sum2;
        return total;
    }

总结:一个值有两个状态,如果值是会反复变化的话,就需要if-else语句两个都要使用。

题目集4  7-3图形继承:

 case 2:
                double width = input.nextDouble();
                double length = input.nextDouble();
                if(width<0.00||length<0.00){
                    System.out.println("Wrong Format");
                }else{
                    Rectangle rectangle1=new Rectangle();
                    rectangle1.setWidth(width);
                    rectangle1.setLength(length);
                    double s=rectangle1.getArea();
                    System.out.println("Rectangle's area:"+String.format("%.2f",rectangle1.getArea()));
                }
                break;

 以选择矩形形式为例,在起始阶段,未了解到继承调用构造方法的语法,并没有rectangle.setLength(lengthx);以及rectangle.setWidth(widthx);这两步,导致程序报错无法运行。后续查阅了论坛,了解到继承的规则以及基本的输入,调用语法,才得以将1输入的内容传入方法中,得以正确调用求面积方法得到答案,其中仍需要注意在求面积方法上,只用调用,不需要再说明传入的内容。

题目集6 7-6实现图形接口与多态性

 初学接口的运用,导致习惯性继承上使用父类子类继承的extends,而接口子类接入方法应该用imolements,通过查看菜鸟教程才得知接口语法有错。

题目集5   7-4统计Java程序中关键词的出现次数

问题:在写代码时不知道如何用List、Set或Map其中的一种接口,对List,Set,Map掌握不好,学习后写过的代码:

 List<KeyWords> list = new ArrayList<>();
		 int r = 0;
		for(int a = 0;a < key.length;a++) {
			KeyWords keyWords = newKeyWords(key[a],0);
 			for(int z = 0;z < c.length;z++) {
 				if(key[a].equals(c[z])) {
 					keyWords.timeIncrement();
 				}
			}
 			//如果关键字次数不为0,则增加到list列表中
 			if(keyWords.getTimes() != 0) {
 				list.add(keyWords);
 			}
		}
	    Iterator<KeyWords> itr = list.iterator();
        while(itr.hasNext()) {
        	KeyWords e = itr.next();
        	System.out.println(e.showStatus());
        } 

总结:List接口其实就是个动态数组,数组的长度可以改变,通过add将需要添加的东西添加进去,如果需要遍历,可以通过Iterator遍历整个list链表。

四、改进建议

1.这次大作业有几道题的圈复杂度还是很高,快接近于20,总体来说虽然比上次低了一些,但是希望下次写代码时也还需要继续关注代码的复杂度问题;

2.对复杂的正则表达式使用掌握的不好,导致题目集4 7-1得不到满分,在今后的学习中会进一步对正则表达式做更深刻的理解;

3.自己对字符串的运用感觉还是运用的太少了 ,对Java当中已经存在过的算法或者功能,库之类的了解也太少了,所以以后多多查点资料,可以解决这方面的问题。

4.想是有规律的数据或者数据一块一块的,组成起来很多地方的话,我之后会优先考虑一下数组的形式去加以完成。

5.在今后的复杂编码中,能使用继承,多态的就使用,能使代码更加的简洁化,父类对象是所有的子类对象公共特征、行为的抽象。

6.今后的编程中,合理的运用多个类,并且一个类只包含一个引起它变化的因素,如果超过一个变化因素,想办法把它分解成多个类。

五、总结

学到的一些知识:

Pattern和Matcher
1.Pattern.split(CharSequence input)(括号里为分割的标识)

用于分割字符串,并返回一个String[].

2.Pattern.matches(String regex,CharSequence input)

快速匹配字符串,适用于匹配一次,且匹配全部字符串

3.Pattern,Matcher

Pattern p=Pattern.compile("\d+"); (括号里为正则表达式)
Matcher m=p.matcher("22bb23"); (括号里为待匹配的字符串)

m.find();返回值为true或false

m.group();得到匹配到的字符串

StringBuilder的用法

StringBuilder sb = new StringBuilder();

1.sb.append();//括号里为字符串

将字符串连接起来

2.sb.toString();//返回与原内容相同的字符串

3.sb.setCharAt(int i,char c);//将第i个代码设置为c(简单理解为替换)

4.sb.insert(int offset, String str);//再指定为之前插入字符串

5.delete(int startIndex,int endIndex):删除起始位置(含)到结尾位置(不含)之间的字符串

4.用StringBuilder输入

以exit标识符为例结束输入(若没输入结果返回"Wrong Format")

Scanner input = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		String str = input.nextLine();
		while(!str.equals("exit")) {
			if(str.length() != 0) {
				sb.append(str);
				sb.append("\n");
			}
			str = input.nextLine();
		}
		if(sb.toString().length() == 0) {
			System.out.println("Wrong Format");
		}

LocalDate.of(int year, int month, int dayOfMonth) 根据参数设置日期,参数分别为年,月,日

5.LocalDate\LocalTime\LocalDateTime类
//自己设置时间,静态方法
LocalDate localdate = LocalDate.of(year,month,day);
LocalTime localtime = localTime.of(hour,day);
LocalDateTime loacalDateTime = LocalDateTime.of(localDate,localTime);
6.close的意义

在java中.close 是关闭的意思。比如session.close(); 意思就是关闭session 同时释放内存

7.字符串转换为字符数组

toCharArray() 方法将字符串转换为字符数组。

8.replace与replaceAll

replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串);

例如:将匹配到的字符串,即双引号里面的内容用空格替代

	 p = Pattern.compile("\"(.*?)\"");
	    for( int j=0;j<i;j++) {
	    	 Matcher m = p.matcher(s);
	    	while(m.find()) {
	    		s=s.replace(m.group()," ");
	    	}

2)replaceAll的参数是regex,即基于正则表达式的替换

例如:将字符串s /* */里面的内容用空替换掉

 String s=sb.toString();
 s=s.replaceAll("/\\*.+\\*/","");
9. arrayList的排序方法

用add将要排序的数据添加到arrayList中,再用

Collections.sort(arrayList)

对arrayList进行排序,例如:

将所有面积放在arrayList,在对其进行排序

 ArrayList<Double> arrayList = new ArrayList<>();

arrayList.add(a[p].getArea());

arrayList.add(b[q].getArea());

arrayList.add(c[r].getArea());

Collections.sort(arrayList);

arrayList的长度获得:

arrayList.size()
10.to CharArray()

toCharArray() 方法将字符串转换为字符数组。

String str = in.next();
        char[] c = str.toCharArray();

第二阶段通过4、5、6三次题目集也结束了,第一次阶段总结的是类设计,而本次的三次题目集基本所有的题目都以类设计为基础,完成题目的构建。在类设计的基础上,通过对继承,多态,接口等多方面学习,认识到类设计不是单一的去设计一个方法完成功能。面向对象编程的思想,也在本次学习真正拉开了序幕。面向对象编程不同于面向过程编程,在创立一个对象后便有明确的功能性,通过继承,多态,接口可以实现不同对象实现不同的功能。其中在类设计上,通过学习类属性的访问权限,初步了解了四种访问权限:public,private,protected,default;以及不同类的类型:实体类,业务类,接口类;对于类设计上,学习的多,代表思路与编程思想变得更为开阔且严谨,开始真正考虑到如何将一个题目设计到恰如其分,其中日期的聚合题目让我深入的感受到,不同的设计思路带来的不同效果。

  对于技能上的学习,在对字符串的校验处理上,通过对正则表达式的深入学习,掌握对复杂数据的校验,截取,替换等,作为一项工具使用,在程序复杂度上大大降低。以及对于list的学习,可以对多对象处理上更为便捷可观,多对象处理上更为有效。还有对于hashmap的学习,对于其中遍历的运用进行了学习,对于多字符校验上有了更广阔的思路。不仅于此,题目集中许多边边角角运用的技能,也是会通过学习得以利用。

  对于课程的学习建议,个人认为目前的PTA便是不错的,有难有易,好上手,但是希望PTA的作业的难度是循序渐进的,而不是一来就是好难的题,这样也有助于学到知识。自我学习上,课程自带的SPOC课程则是选择之一,我们仍可自己去选择去论坛学习或者其他网课上学习。在实验上,目前进行的农夫过河的迭代性编程,面对同一个问题随着技术加深,我们需要运用更为上层的知识解决同一个问题,这是有趣也充满挑战的。线下课程中,希望老师不仅可以有对知识的讲解,与编程思想的演练,更可以对pta或者实验的难题加以点评与讲解,让作业不会得过且过,而是让我们更为深刻的了解一道题目应该如何去设计。作为学生自身,已经了解到这是一门需要自我探究,自我学习的课程。时间,精力,投入,缺一不可,不去假大空,而是去真正的做。

 首先感谢老师的付出,再而感谢还在学习的自己。希望有更好的心态迎接第三阶段!

posted @ 2021-11-12 19:52  azaz+  阅读(236)  评论(0)    收藏  举报