OO第三单元小结
概论
这一单元的主要内容是JML,通过给定的JML语言来构建符合规范的代码,在这一单元更加了解了形式化表达和规范的重要性。在学习JML的过程中能感受到一些离散数学中学到的命题逻辑等形式化表达语言,所以这一单元的学习更加了解到了所谓的“契约式”思想设计。所以以下将简单总结以下这一单元学习的内容。
JML基础和工具链
JML基础
JML的表达式分为原子表达式、量化表达式和集合表达式。
原子表达式
表达式 | 含义 |
---|---|
\result | 方法执行后的返回值 |
\old(expr) | 相应方法执行前的值 |
\not_assigned(x,y,...) | 表示变量是否被赋值 |
\not_modified(x,y,...) | 表示变量是否被修改 |
\nonnullelements(container ) |
表示container中没有null对象 |
\type(type) | 返回类型type对应的类型 |
\typeof(expr) | 返回expr对应的准确类型 |
量化表达式
表达式 | 含义 |
---|---|
\forall | 全称量词 |
\exists | 存在量词 |
\sum | 返回给定范围内表达式的和 |
\product | 返回给定范围内表达式的连乘 |
\max | 返回给定范围内表达式的最大值 |
\min | 返回给定范围内表达式的最小值 |
\num_of | 返回指定变量中满足相应条件的取值个数 |
集合表达式
集合构造表达式的一般形式为:new ST {T x|R(x)&&P(x)},其中的R(x)对应集合中x的范围,通常是来自于某个既有集合中的元素,如s.has(x),P(x)对应x取值的约束。
方法规格
规格 | 含义 |
---|---|
pre-condition | 前置条件通过requires子句来表示:requires P; |
post-condition | 后置条件通过ensures子句来表示:ensures P; |
side-effects | 副作用指方法在执行过程中会修改对象的属性数据或者类的静态成员数据,从而给后续方法的执行带来影响。 |
signals | 结构为signals (***Exception e) b_expr; ,意思是当b_expr 为true 时,方法会抛出括号中给出的相应异常e |
类型规格
类型规格是对数据类型所设计的限制规则。主要涉及两类,不变式限制和约束限制。
- 不变式(invariant)是要求在所有可见状态下都必须满足的特性,语法上定义
invariant P
,其中invariant
为关键词,P
为谓词。 - 状态变化约束constraint。对象的状态在变化时往往也许满足一些约束,这种约束本质上也是一种不变式。
方法与类型规格的关系
静态成员初始化 | 有状态静态方法 | 有状态构造方法 | 有状态非静态方法 | |
---|---|---|---|---|
static invariant | 建立 | 保持 | 保持 | 保持 |
instance invariant | (无关) | (无关) | 建立 | 保持,除非是finalizer方法 |
静态成员初始化 | 有状态静态方法 | 有状态构造方法 | 有状态非静态方法 | |
---|---|---|---|---|
static constraint | (无关) | 遵从 | 遵从 | 遵从 |
instance constraint | (无关) | (无关) | (无关) | 遵从 |
SMT Solver
全称为Satisfiability modulo theories Solver。过去十年,SMT(Satisfiability modulo theories)求解器在形式化方法、程序语言、软件工程、以及计算机安全、计算机系统等领域得到了广泛应用。
部署open_jml失败,考虑到边际效应,花费大量的时间部署这样的工具链但是并没有什么用,遂放弃。
JMLUnitNG
随机生成测试用例,但是覆盖性较差。
JUnit
一种“白盒测试”方法,可以在一边开发的过程中一边使用。本次实验也用到了这一方法,课堂也花费了大量的时间来讲解这一内容,具体的就不再赘述。
作业总结
第一次作业
对于第一次作业,其实说实话自己太掉以轻心了。最开始就以为照着JML来写代码简直就是“看图说话”,所以一个晚上就完成了代码。然后就只提交了一次就通过了中测,之后就没有检查也没有测试。但是当互测出来发现自己根本没进入互测,互测结束之后看见自己强测为零分。当时就给了我蒙头一棒。
之后检查发现是自己对于isCircle
函数的理解错误,这个函数的名字让我以为是用来判断两个人是否存在一个环,所以对应的我的算法就写成了判断图中是否存在一个环包含两个节点。
这也让我认识到自己需要认真读JML的规格说明,而不是自作聪明。
所以互测也没有什么好说的。
第二次作业
有了第一次作业的惨痛教训,第二次作业我就更小心更认真的阅读了JML,根据规格来写代码。
但是这一次居然也没有进入互测是我没有想到的,发现是算法的问题导致超时,而没有出现其他的问题。所以我想这一次虽然和第一次结果一样,但是仔细分析的话并不是JML的问题,具体问题具体分析,关于算法的问题应该是大一学习DS的漏洞。
架构
第二次作业增加了group类,但group内也是一些基本的关于容器的操作,在这里也不再赘述。给出UML图。
第三次作业
第三次作业在第二次作业的基础上增加了更多的方法,最重要的还是其中对于图算法的考察(说实话我不太明白为什么这一单元考这么多算法)。主要的参考算法列在这里,就不重复造轮子了:
dijkstra算法
tarjan算法
这一单元倒是进入了互测,但是多少还是出现了一些bug。后查发现是strongLinked条件出错,导致算法错误。
而由于前两次没进入互测,所以这一次根本不知道从哪里开始互测,也就没有互测。当作给做慈善了。
反思与总结
这一单元据说是最简单的一个单元,但是我做的完全不理想。总结一下是对于这一单元太过于轻视,所花费的时间还不到前两个单元的一半。除此之外,阅读大量的JML让我觉得挺枯燥的,有时候也会产生疑问——“JML存在的意义是什么?”为什么用人话都能说明白的东西还要用这种繁琐的语言来表达?难道现在真的有公司开发产品会用到JML吗?当百度JML时发现结果全是北航的博客,网上的资料都寥寥无几。而在这一单元给的代码和实验里面的JML或多或少都有一些错误,这也证明了这种繁琐的工具可能在逐渐被淘汰掉。
当然这一单元学的很糟糕或许我并没有什么发言权,但是也希望老师和助教能听听其他同学的意见。不仅仅是JML,实验报告要求的工具链很多人都无法部署成功。这一单元,并没多少收获,除了一些图论中的算法,但是我想这或许不是这门课和这一个单元的重点。
当然这仅仅是对JML本身和对一些多年无人维护的工具链的看法,和课程组无关。
希望最后一个单元能好好整一下,弥补一下这一单元的惨痛失败。