OO第三单元总结

OO第三单元总结

目录
  • OO第三单元总结
    • JML基础语法
    • 工具链应用
    • JMLUnitNG
    • 第九次作业
    • 第十次作业
    • 第十一次作业
    • BUG分析
    • HACK策略
    • 第三单元感想体会


JML语言的理论基础、应用工具链情况

JML基础语法
  • requires : requires a ,即为前置条件语句,在方法满足条件的情况下实现之后的功能。
  • ensure:ensure a ,即为后置条件语句,在满足ensure对应require前置条件方法执行后对各个容器变量改变的要求。
  • assign:即标明方法执行后的副作用,指明对无关容器变量的影响。
  • public normal_behavior:正常处理部分。
  • public exceptional_behavior:抛出异常部分。
  • \forall:全称量词,具体实现采用遍历容器的for代码实现,对于单层遍历,使用Arraylist遍历较遍历Hashmap复杂度更低。
  • \exists:存在量词,具体为实现选取容器中的特定元素,使用key与value一一映射的Hashmap即可。
  • \old:old a ,表示方法使用改变a之前的值,常见于表示增加删除容器元素后容器的容量变化。
工具链应用
  • Junit:单元检测
  • OpenJml:JML语法检测
  • JMLUnitNG:生成测试样例,主要为爆破边界。

部署SMT Solver

折腾了半天jdk,魔改demo,还是会有各种奇怪的报错,遂quit。根据部署成功的同学的介绍,由于SMT在遇到\forall, \exists等复杂逻辑语句时会报错,对我们大学的OO单元作业用处并不太大。

部署JMLUnitNG/JMLUnit

JMLUnitNG

总算配成功了orz
根据J哥的博客,部署好文件树后,输入一下代码来生成对MyGroup的测试,

java -jar jmlunitng.jar jmlunit/MyGroup.java
javac -cp jmlunitng.jar jmlunit/*.java
java -jar openjml.jar -rac jmlunit/MyGroup.java
java -cp jmlunitng.jar jmlunit.MyGroup_JML_Test

最后得到如下反馈

[TestNG] Running:
  Command line suite

Passed: racEnabled()
Passed: constructor MyGroup(-2147483648)
Passed: constructor MyGroup(0)
Passed: constructor MyGroup(2147483647)
Failed: <>.addPerson(null)
Failed: <>.addPerson(null)
Failed: <>.delPerson(null)
Failed: <>.delPerson(null)
Failed: <>.delPerson(null)
Passed:<>.equals(null)
Passed:<>.equals(null)
Passed:<>.equals(null)
Passed: <>.equals(java.lang.Object@574caa3f)
Passed: <>.equals(java.lang.Object@64cee07)
Passed: <>.equals(java.lang.Object@1761e840)
Passed: <>.getAgeMean()
Passed: <>.getAgeMean()
Passed: <>.getAgeMean()
Passed: <>.getAgeVar()
Passed: <>.getAgeVar()
Passed: <>.getAgeVar()
Passed: <>.getConflictSum()
Passed: <>.getConflictSum()
Passed: <>.getConflictSum()
Passed: <>.getId()
Passed: <>.getId()
Passed: <>.getId()
Passed: <>.getRelationSum()
Passed: <>.getRelationSum()
Passed: <>.getValueSum()
Passed: <>.getValueSum()
Passed: <>.getValueSum()
Failed: <>.hasPerson(null)
Failed: <>.hasPerson(null)
Failed: <>.hasPerson(null)
Passed: <>.updatePerson(null)
Passed: <>.updatePerson(null)
Passed: <>.updatePerson(null)
Passed: <>.downloadPerson(null)
Passed: <>.downloadPerson(null)
Passed: <>.downloadPerson(null)
Failed: <>.updateLink(null, null)
Failed: <>.updateLink(null, null)
Failed: <>.updateLink(null, null)

===============================================
Command line suite
Total tests run: 44, Failures: 11, Skips: 0
===============================================

可以发现JUMLUnitNG生成的测试样例大部分为null,INT_MAX,0,等等极其边界条件,针对本单元作业没有太大作用。

架构设计与模型构建策略

第九次作业

由于是新单元的第一次作业,整体结构直接根据官方的接口,建立MyPerson,Mynetwork三个大类即可,接口的实现绝大部分可以照搬JML翻译,其中需要考量的有两点:iscircle的算法选择,与不同属性的容器选择。

  • isclrcle:采用BFS:由于DFS存在爆栈的可能,担心被某些饥渴的狼人中,遂放弃。
  • 容器选择:用于Hashmap有红黑树等的隐形优化,除去要求且仅要求每次遍历的数据使用Arraylist外,其余的使用Hashmap存储。
第十次作业

第二次作业相较于第一次作业主要新加Group大类,并根据Goup的成员实现group中所有成员年龄平均值,方差等方法,值得思考的同第九次作业有两点:Group容器的选择;qgrs,qgvs如何优化二重遍历,避免O(n^2)。

  • Group容器的构造:由于Group中的方法对遍历group全体成员与选取单个成员都有较多的要求,因此我选择分别建立private HashMap people1 = new HashMap<>(8192)private ArrayList people2 = new ArrayList<>(8192)两个容器来存取group中的person信息,在选取判断特定成员时,使用Hashamap,遍历全体时使用Arraylist,能有效缩短由于Hashmap预留的空间而导致遍历全部的key-value时间开销过大。并根据Group存储person的最大数量限制,为两个容器开设8192的初始容量,避免后续添加person时单独开设空间的时间浪费。
  • 二重遍历的优化:采用及时建立缓冲的策略,在addRelation与addtoGroup的过程中及时更新Group中的relationSum与valueSum。
第十一次作业

第三次作业的难点集中在三个方法的实现qmp, qsl, qbs,主要的设计与时间投入也集中在这块。

  • qmp:采用Dijsktra + Priorityqueue优化的算法。
  • qsl:根据JML的ensure分析,先通过DFS遍历得到所有的路径,if:不存在节点个数大于等于3的路径,return false;else:选取该路径,遍历该路径上除去首尾的所有点,遮掩该点后再次DFS,判断有无第二条路径。
  • qbs:采用并查集 + 路径压缩的算法,主要代码如下,分别进行的功能。
	public Person findPa(Person son) {
        if (!pre.get(son).equals(son)) {
            pre.replace(son, findPa(pre.get(son)));
        }
        return pre.get(son);
    }

	void merge(Person son1,Person son2) {
        Person papa1 = findPa(son1);
        Person papa2 = findPa(son2);
        if (!papa1.equals(papa2)) {
            pre.replace(papa2, papa1);
        }
    }

bug和修复情况

BUG分析
  • 第一次由于首次接触JML,书写时照搬JML语句people.get(i) == person,而没使用重写的equal方法。
  • 第三次中用手搓DIJ + PriorityQueue荣幸获得边界tle,与同学代码比对后发现具体实现没有太大差异,最后发现是Person.acq使用hashmap时初始化大小过大,导致qmp遍历时耗时过多,导致tle。emmm,出这种错蛮无语的,当然也说明测试时极端数据没有构造的太好。
HACK策略
  • 第一次和第二次都没中。
  • 第三次主要针对qmp构造极限数目的点连乘一条直线,针对qsl的多重深搜构造多环图,Hack刀了3个小伙伴。

阐述对规格撰写和理解上的心得体会

第三单元感想体会

自我感觉第三单元的整体难度较第二单元有所下降,主要重点集中在对JML的理解,即该方法实现的目的是什么来思考,而不是机械的翻译。第三次作业由于涉及性能要求,考察了一定算法知识,思考算法层面的时间占据了绝大部分。另外一点便是由于JML已经给出了大部分的代码框架,且群佬除我,因此有一点微小的错误都会造成强测直接被专业团队愉快送走,对我们自动化测试与极端测试数据的构造都有了极大要求,all in all ,对拍真香。

你可能感兴趣的:(OO第三单元总结)