OO第三单元总结

一、JML的梳理与总结

JML的注释结构:

1requires:前置条件,即执行方法前应当满足的条件。

2assignable:副作用的范围限定,其中 \nothing表示不对任何属性进行修改。

3ensures:后置条件,即在执行方法后应当满足的条件。

在作业中常见的JML关键字:

\result:方法执行结果(非void)。

\old(expr):表示表达式expr在方法执行前的取值。

\not_assigned(x,y...)括号中的变量在方法执行过程中的赋值是否被改变。

\forall:对于在范围内的元素所有都满足某些条件。

\exists:对于在范围内的元素中至少存在一个元素能满足条件。

\sum:在范围内所有元素之和。

\max:在范围内中最大的元素。

\min :在范围内中最小的元素。

<==>:等价关系操作符。

==>:推理操作符号。

normal_behavior:正常行为。

exceptional_behavior:异常行为。

signals(e):抛出异常e。

在作业中值得注意的是\sum、\exists、\forall只对紧跟其后的表达式进行操作,而不是对其后面所有的变量进行操作,这些点的理解对于在作业中一些使用了双重循环的规格的正确的理解有着重要帮助。

 应用工具链:

 OpenJML:使用SMT Solver来检测程序是否满足所设计的规格

链接:http://www.openjml.org/

 JMLUnitNG:根据规格自动生成测试数据。

链接:http://insttech.secretninjaformalmethods.org/software/jmlunitng/

部署JMLUnitNG/JMLUnit

注意JAVA的版本应配置为java8,不然会出现报错。此外在进行测试时需要对包名进行修改,不然也会出现报错。

文件分布

OO第三单元总结_第1张图片

 

用java -jar openjml.jar -check test/Group.java test/Person.java来检查规格的语法,然后??????

OO第三单元总结_第2张图片

居然对三目运算符报错??(气抖冷哭,什么时候三目运算符才能站起来),在找不到较好的解决方法的情况下,于是我将这几句进行了删除(出问题了嘛,砍了就好)。

然后java -jar openjml.jar -rac test/Group.java test/Person.java

结果??黑人问号脸.jpg

改用静态java -jar openjml.jar -esc test/Group.java test/Person.java终于能过了。

使用javac -cp jmlunitng.jar test/*.java

来生成带有运行时检查的class文件

最后使用java -cp jmlunitng.jar test_JML_Test来生成测试数据

Passed: static compare(-2147483648, -2147483648)

Failed: static compare(0, -2147483648)

Failed: static compare(2147483647, -2147483648)

Passed: static compare(-2147483648, 0)

Passed: static compare(0, 0)

Passed: static compare(2147483647, 0)

Failed: static compare(-2147483648, 2147483647)

Passed: static compare(0, 2147483647)

Passed: static compare(2147483647, 2147483647)

Passed: static main(null)

可以看到其中的数据多半是一些int的上下限、0、空等极端情况,但是在作业的限定下这些情况大部分都很难出现,指望他去检查出BUG多半是不可能的,抛开作业来讲,一个程序难道不是首先应该保证大部分数据的正确性,然后再考虑边界数据吗?自动生成的数据完全又没有随机性,只考虑边界情况显得有些本末倒置。

 

作业架构分析:

整体结构与官方建议并无太大差别,所以不予分析。

第一次作业:

Mynetwork复杂度:

OO第三单元总结_第3张图片

MyPerson复杂度

OO第三单元总结_第4张图片

 在第一次作业中对于JML的考察比较基础,尾翼有一点难度的iscircle我使用了BFS算法进行了解决,在第一次作业中只需要完完全全照着规格来编写代码即可完成要求。

第二次作业:

MyGroup复杂度分析

OO第三单元总结_第5张图片

 

MyNetwork复杂度分析

 

OO第三单元总结_第6张图片

MyGroup复杂度分析

OO第三单元总结_第7张图片

在第二次作业中新增加了Mygroup这一个类,这个类可以理解为群组,在第二次作业中只是照着规格写是不够的(大部分可以,但是少数需要优化算法),还必须对算法进行复杂度分析,不然就可能像我一样CTLE,为了简化算法必须在每次往群组里加人时都更新一遍相应的信息,比如queryValue就需要遍历群组中现有的人然后更新valuesum的值,值得注意的是有可能出现先加人,后加关系的情况,所以需要在加关系时对所有的Group检查,看其中是否包含有两人,如果有则需要对相应的数值进行更新。另外在往群里加人时的上限是1111,这个限制并不是数据应该保证的,而是代码应该保证的,由于理解错了这一点导致出现了人数溢出这一错误。

第三次作业

MyGroup复杂度分析

OO第三单元总结_第8张图片

 

MyNetwork复杂度分析

OO第三单元总结_第9张图片

 

OO第三单元总结_第10张图片

MyPerson复杂度分析

OO第三单元总结_第11张图片

在第三次作业中主要是增加了借钱和一些诸如最短路径和双联通之类的图论问题,在输出联通块个数时我采用了并查集的方法,在每次加人、加关系的时候更新联通块的数量。最短路径算法并没有使用堆优化的迪杰斯特拉算法,导致超时的可能性很大,判断两人是否是强联通可以先使用dfs找出一条路径(直接相连的除外)然后依次去除其中的点(起点终点除外),如果起点和终点仍然联通则说明满足条件,反之则不满足,这种做法略显暴力,在时间复杂度上也比较高,算不上一个优解。

BUG分析

  这三次出现在对于JML理解上的BUG其实很少,只有对于那个require的理解出现了偏差(以为是数据满足不会往群组里加超过1111个人最后在加入时进行特判即可),主要问题出现在一些算法的复杂度分析不到位,出现了超时问题(没有分析到双重循环的复杂度可能会导致超时问题,在加人加关系时进行数据更新,第三次作业中普通的迪杰斯特拉算法容易超时,需要使用堆优化的迪杰斯特拉算法),此外在图论部分的算法当中有些算法不够熟悉,出现了一些低级失误,比如初始化的值太小导致最短路径找错了,而在自我测试的时候又偏偏设置的value都比较小没有触到错误的边界,等等这些问题导致第三次作业翻车。

心得体会

关于JML:在最开始的时候我对JML的理解是对JAVA程序中的架构的一种描述性语言,在经过三次作业的摧残后,我现在JML作用的并不是对程序的实现过程的描述性语言,而是对于程序所实现的功能做出的描述,具体怎么实现则有编写程序者来完成,只要能满足规格的限定,完成相应的目的即可。大部分JML的阅读还是比较容易理解的,可以很轻易地知道该方法具体是要实现什么功能,少部分JML可能看上去有些不知所云,但是可以结合方法名来进行推测,比如blocksum的规格,一看上去怎么也看不出来他是在干什么,照着规格写又有可能会超时,但是结合该方法的方法名可以推测出他是要求出图中联通块的个数,从而可以使用并查集来解决该问题(同时可以更改iscircle的方法为并查集)。

关于作业:对于这三次作业我个人觉得第一次作业主要是考察基本的JML阅读理解,第二次作业则是更注重复杂度分析,第三次作业则是考察图论算法,在这三次作业中,由于自动测试方面还不太会用,而自我测试中构造数据不够全面而导致一些BUG没有测出来,确实把我坑的很惨。在这三次作业中其实对程序架构的思考比较少(毕竟只用来实现接口),主要还是对于JML阅读,算法以及复杂度比较多,在实验中考察了对于JMl的完善书写,说实话反向操作还是有些难度,有时候不知道条件是否补充完善,就特别难受,关于JML的书写方面还是不太熟练。

 

 

 

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