OO第二阶段习题集总结
(20201217-马天奇)
一、 前言:
三个的题目集均涉及到了Java面向对象的核心技术特性:封装性,继承性,多态性。
题目集四:图形继承的题目中,考察了代码复用,继承重写@Override和构造方法链的调用。日期问题的面向对象设计中,类与类的关系中用到了聚合关系,通过分析类图,代码顺理成章,最后使用自己的代码生成的类图与题目中的类图一致,难度适中。水文数据校验处理运用正则表达式进行查找匹配这部分难度还是比较大的,对于新知识没有进行深入的学习,掌握不是很熟练,编程过程中思路很模糊,编写的正则表达式过于复杂,匹配不精准,修改起来也很麻烦,没有得到全分。
题目集五:通过找出最长单词的题目中,用到了split方法拆分字符串,属于正则表达式中的一个运用。加入了数组排序处理,和运用不同排序算法对数据进行排序,比较简单,通过此复习巩固了这部分的知识。再次运用聚合关系对日期问题进行设计,功能实现与题目集四中的相同,但类图不同,类与类之间的关系发生了变化,难度适中。统计Java程序中关键词的出现次数涉及到了正则表达式和Java集合框架的应用,都是需要自学的新知识,难度比较大。
题目集六:经过前两次正则表达式的练习与学习,题目集六中的有关正则表示式的题目就显的很简单了,很快便能准确快速地提交并通过检测。此外复习了关于字符串的处理,进行字符排序,运用java.util.Arrays.sort.便能对数组进行快速排序。在图形继承多态中涉及了Arrays及Collections的简单应用,泛型运用:ArrayList常用方法及和数组的关系,难度偏难。实现图形接口及多态性中充分用到了Java面向对象的特性,对接口的声明和实现进行了实战运用,难度适中。
二、 设计与分析:
(1) 题目集4(7-2)、题目集5(7-4)两种日期类聚合设计的优劣比较。
题目集4 (7-2)类图:

圈复杂度测试:

从类图可看出题目集四(7-2)中类的关系为组合,组合是一种聚合的限制形式,一个对象必须依赖另一个对象的存在而存在。其中Day,Month,Year,DateUtil 这几个类高度相互依赖即高度耦合,维护成本高。当然在编码过程中很明显能感觉到,当一个类中的参数传递出错时,跟着其他几个类也要随之做相应的修改,过程很繁琐。在PTA平台进行提交测试时,前n天、后n天和间隔日期测试点总是报错。排查后才找到原因是在Day类中对构造对象参数进行修改后没有修改Dateutil类中对象参数,导致参数传递错误。由此可见维护成本之高。但其优点是不破坏封装性,整体类可以对局部类进行包装。
题目集5 (7-5)类图:

圈复杂度测试:

从类图得知题目集五(7-5)中类的关系为关联,它是一种结构化关系。其中Dateutil类同时对应Year,Month,Day类。Dateutil类通过调用其他与之相关联类中的方法实现功能,关系对象出现在实例变量中。类与类之间相互独立,耦合度低,维护成本较组合关系少很多。
综上所述,两者相比较,关联关系类与类之间相互独立,耦合度低,维护成本低;而组合关系中类与类之间高度依赖,导致耦合度很高,维护成本高。在处理日期问题上关联关系相对组合关系要方便一些。
(2) 题目集4(7-3)、题目集6(7-5、7-6)三种渐进式图形继承设计的思路与技术运用(封装、继承、多态、接口等)
题目集4(7-3)类图:

此题主要运用继承,首先创建一个超类Shape,其中包含了其他子类中重复出现的公共方法getArea和Shape方法。声明子类时将extends关键字放在class之后,子类中除一些变量声明、构造有参和无参方法、getter and setter外,相同的方法有getArea,但父类中定义的方法不能满足每个子类中的要求,比如:在Circle类中要计算的是圆的面积,在Rectange类中则需要计算的是矩形的面积,两种面积计算方式是不同的,这就需要将父类中的getArea方法进行重写,标注@Override,子类getArea方法中分别写相应的计算公式。这样写减少了代码的重复,不会显的很臃肿。
在主方法中由于运用了switch选择关系,输入的值可以直接被被选择类中的方法所用,没有构造对象,在主方法中可直接调用类中的方法。


题目集6(7-5)类图:

本题主要运用了抽象类,在Java中抽象类表示的也是一种继承关系。首先根据指导书中的继承结构层次图创建好Shape抽象类,写好gerArea(),toString(),validate()三个抽象方法, 在三个子类中运用多态,对抽象类中的抽象方法进行重写以满足各自方法需求。当然继承同样还是减少了代码的重复量;多态,可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

由于在输入数据时输入的是个数,所有几何图形的参数,所以在主方法中用到了ArrayList类,用来处理输入的大量数据。添加数据用到了.add方法,访问数据时用到了.get方法,并使用new + 类名将数据对号入座。最后用list.get(i).getArea();list.get(i).toString();list.get(i).validate(); 得到最后相应结果。

题目集6(7-6)类图:

此题中运用到了接口,明确接口是抽象类型即抽象方法的集合,不属于类,以免出错。首先根据类图,使用interface来定义GetArea接口,在其中写入要实现的方法getArea()。在类声明中,Implements关键字放在class声明后面。Rectangle和Circle类使用implements关键字实现接口。实现接口在重写方法时要保持一致的方法名getArea(),并且应该保持相同返回值类型。



主方法中构造了Circle data和Rectangle data对象用来传递数据。

(3) 三次题目集中用到的正则表达式技术的分析总结
刚开始接触正则表达式确实比较懵,看了几次都不是很理解,不过边用边学还是有一定作用的,慢慢对照要求和正则表达式表进行比对还是能正确写出来的。正则表达式描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。很方便的就能找到字符串中的字符,避免了程序代码过于复杂化。在使用时要注意细心,时常会出现匹配不精准的情况。
题目集四:
"^\\s*|\\s*$" 判断连续输入为空,”|”
"(.*)\\t(.*)\\t(.*)\\t(.*)\\t(.*)" 根据所给判断数据输入合法性
"((([1-9]{1}|[1-9][0-9]{1}|[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,1}[0-9]{0,1})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))/2/29)) ([02468]|1[02468]|2[02]):00" 根据时间格式判断时间
"(([1-9][0-9]{0,2})|(([1-9][0-9]{0,2})(\\.[0-9]{1,3})))" 判断水位数据
"(([1-9]|[1-9][0])(\\.[0-9]{2}))" 判断开度
题目集五:
replaceAll("//.*", " ").replaceAll("\".*\"", " ") 去掉"//"后和的内容以及双引号里的内容
replaceAll("/\\*\\s*.*\\s*\\*/"," "); 去掉"/* */"里的内容
“\\b + gic []+"\\b"; 创建关键词的正则表达式
题目集六:
QQ号校验:
"^[0]{1}" 判断首位是否为0
"^\\d{5,15}$" 判断位数是否和要求
验证码校验:
"^[0-9a-zA-Z]{4}$" 匹配所有数字和所有字母且总共4位
学号校验:
根据班级情况进行学号匹配
"20201[1-7][0-3][0-9]|20201[1-7]40"
"202061[0-3][0-9]|20206140"
"20207[123][0-3][0-9]20207[123]40"
"20208[12][0-3][0-9]|20208[12]40"
以上便是题目集中涉及到的正则表达式,虽然一开始很茫然,但慢慢跟着正则表达式手册上的规则一步步做,还是能够写出来的。
(4) 题目集5(7-4)中Java集合框架应用的分析总结
思路:将所有关键字存入字符串数组中,再利用for循环和正则表达式找每个关键字的出现次数,并计数,最后输出。

Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。
HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
Map的遍历:先调用entrySet()得到Set<Map.Entry<K,V>>集合,直接使用foreach()进行遍历。
得到映射表中所有的value值:values()方法。
判断是否包含key:containsKey()方法。
删除某个映射关系:remove()方法。
三、 踩坑心得:
(1) 日期问题面向对象设计中,主方法的圈复杂度过高:在第三种情况中,要对输入的两个日期进行判断比较,用到了大量的if-else语句;前两种情况中,对数据正确性判断和天数判断也使用到了if-else语句。


(2) 编程过程中要注意代码输入的准确性。在题目集六7-5中,抽象类中的抽象方法toString输入错误为toSting,导致程序输出结果为一串地址。为此问题排查耗费了很多时间。有空多在TT上练打字,提高打字准确率和速度。

(3) 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
(4) 日期问题面向对象设计在PTA平台测试时下n天和前n天的最大整型值测试均为运行超时,多次提交后还是如此,后来把N值的声明从int改为long即可通过测试。
(5) 日期问题面向对象设计中,判断2月天数涉及到用month的一个数组,但在PTA平台测试时天数差的测试点中有运行超时,经过多次测试发现month的数组超限了,month的范围判断要在数组之后,不得不在输入month的时候加一个判断,使月份数保持在1-12之间。

四、 改进建议:
(1) 题目集四中的7-3可以尝试在Shape抽象类中加入抽象方法getVolume,使求体积的方法得以在Box和Ball两个类中继承复用。
(2) 正则表达式要严格按照手册规则进行编写,并且要细心认真,稍有不慎便会导致匹配结果不准确。遇到比较长的正则表达式修改起来是非常麻烦的。
(3) 建立面向对象编程思想,逐渐走出C语言的思考圈。大部分的代码圈复杂度都在10以下,归功于对Java面向对象编程的理解,但也有超过10的代码,其中大多涉及选择判断,有大量的 if-else语句,以后尽量要摆脱if语句。
题目集四:

题目集五:

题目集六:

五、 总结:
通过第二阶段题目集的训练,初步建立了面向对象编程的思想,学会了使用面向对象的封装性、继承性及多态性解题,代码的复用率明显有提高。深入理解继承与多态的原理及用法,ArrayList常用方法及和数组的关系以及泛型的运用。同时在解题过程中学会了一些细节方法,例如:String.format,split,Arrays及Collections的简单应用。还有接口的声明与实现,将老师讲的内容通过做题的方式巩固了一遍,加深了理解。做题时遇到问题时会去查资料,慢慢的明白了很多相关的知识,例如关于抽象类就了解了很多:抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。单一职责原则:每个类/方法围绕一个主题。迪米特原则:不要和陌生人说话,只和你的直接朋友交流。这两个原则始终贯穿整个编程过程,这也是最大的收获之一。通过做关于正则表达式的题目,也发现了自己的不足:学习效率不高,习题集四、五中有关正则表达式的题目没有得到全分,根本原因是没有投入足够的时间去学习,只是大概看一下,一知半解,运用的时候不熟练。从根本上解决这个问题还是要从被动学习转变为主动学习,投入时间去钻研,克服拖延症,提高学习效率。

浙公网安备 33010602011771号