一、梳理JML语言的理论基础

1、jml的注释结构

  jml注释语言的每一行都以@作为开始,若是块注释,则需要在注释块的首尾使用/*@ 与@*/

2、jml的表达式体系

1、原子表达式

  表达式可以看作是一个原子类型,常见的有\result表达式(用于表达某个方法执行后的结果)、\old表达式(用来表示某个对象执行某操作之前的值)。

2、量化表达式

  量化表达式是对给定范围内对象批量操作的表达式,其存在大大简化了jml语言,常见的有\forall表达式(范围内对象,都要满足某要求)、\exists表达式(范围内存在对象,满足某要求)、以及\sum表达式、\product表达式、\max表达式等数学方法的量化表达式

3、集合表达式

  用来在jml规格中构造一个集合(容器),来简化jml规格

4、操作符

  包括算数操作符和逻辑操作符。例如等价操作符<==> 与 ==,其中特别要注意的是<==> 与 ==这样的操作符,优先级是不一样的!

  此外操作符还包括变量引用操作符,例如\nothing指示一个空,\everything指示一个全集。

3、jml的方法规格

  我们使用与学习的方法规格只是最基础的部分,核心内容是三方面:前置条件、后置条件、副作用限定。

1、前置条件

  前置条件使用requires语句来表示,requires P意味着需要确保P的值为真。需要注意的是,requires语句如果多行一起出现,是并列条件,需要全部满足。

2、后置条件

  后置条件使用ensures语句来表示,ensures P意味着需要确保P的值为真。同样,ensures语句如果多行一起出现,是并列条件,需要全部满足。

3、副作用限定

  在方法执行时,为了满足前置条件与后置条件,我们可能会对对象做一些与前置条件和后置条件无关的改动,也就是副作用。有时候需要通过副作用限定来对方法实现进行约束。

  这里,我们可以选择assignble和modifiable。

  assignble 表示可赋值,而 modifiable 则表示可修改。虽然二者有细微的差异,在大部分情况 下,二者可交换使用。

  这两个关键词既可以约束特定的对象,表示更改特定对象。也可以选择约束\nothing 和 \everything这样的关键词,来表示什么都不更改,或是全部更改。

4、其他

  当前置条件与后置条件需要对多个对象进行约束时,可以与用\forall或者\exists表达式结合使用。

  我们使用signals语句,来表示异常处理,语句signals (***Exception e) b_expr 的意思是当 b_expr 为 true 时,方法会抛出括号中给出 的相应异常e。

4、jml的类型规格

  不变式(invariant),语法上定义 invariant P ,其中 invariant 为关 键词, P 为谓词,表示要求在所有可见状态下都必须满足的特性。

  状态变化约束(constraint),用来对前序可见状态和当前可见状态的 关系进行约束。

5、总结

  jml语言是一套逻辑严密的注释语言体系,通过对方法行为的描述,预防bug的出现,并使得检查过程比原先轻松,提高了代码的可维护性。

二、jml应用工具链情况

  首先,是jml语言的编写,可以使用专门的jml编译器。

  jml规格的校验,可以使用openjml。

  JMLUnitNG可以根据规格的实现自动生成TestNG测试样例。

三、部署JMLUnitNG

1、测试代码

package demo;
public class Demo {
private /*@ spec_public @*/ int[] nodeList; public Demo(int[] nodeList) {
this.nodeList = new int[16];
} /*@ requires index >= 0 && index < size();
@ assignable \nothing;
@ ensures \result == nodes[index];
@*/
public /*@pure@*/ int getNode(int index){
if (index >= 0 && index < size()) {
return nodeList[index];
} else {
return 0;
}
} //@ ensures \result == (nodes.length >= 2);
public /*@pure@*/ boolean isValid(){
boolean ret = false;
if (nodeList.length >= 2) {
ret = true;
}
return ret;
} public static void main(String[] args){ } }

2、测试方法

  首先,尽管已经有很多前人感谢过伦佬了,但我还是要在这里郑重地再感谢一次伦佬。

3、测试结果

[TestNG] Running:
Command line suite

Passed: racEnabled()
Passed: constructor Demo()
Passed: <<demo.Demo@1a8f2434>>.getNode(-2147483648)
Passed: <<demo.Demo@5f5a92bb>>.getNode(0)
Passed: <<demo.Demo@376b9c22>>.getNode(2147483647)
Passed: <<demo.Demo@54768a01>>.isValid()
Passed: static main(null)
Passed: static main({})

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

4、测试思考

  这个自动化测试emmmm,实际上,只是测试了几个边界条件,似乎正能起到一个锦上添花的作用。

四、架构设计

1、第一次作业

  在pathcontainer中,我的选择是构造三个hashmap,一个用path作为key,pathid作为value。另一个用pathid作为key,path作为value。(这里需要在mypath类中重构path对象的hashcode方法)。这两个hashmap实现了path的快速查找和改动(总有一个hashmap可以用key查找,查找出来的value作为另一个hashmap的key)。第三个hashmap,使用node作为key,node的数目作为value,用来,存储当前容器内的节点数量。

  在path中,除了本身的节点数组外,我还构造了一个hashmap,用于判断path中是否含有某node。

2、第二次作业

  本次作业要求,在第一次作业的基础上,加入了判断两个节点是否联通,两个点是否能构成一条边,以及得到两个节点间的最短路径。

  我并没有对第一次的构造进行改动,而是在第一次作业的基础上又构造了两个静态数组,一个hashmap,和一个arraylist,其中hashmap是保存节点与映射节点的关系(我将图内的节点映射到了0到nodesize内),具体做法是,先检查arraylist如果arraylist不为空,从arraylist内取出一个可映射的值,与当前节点映射。否则,当前映射id与当前节点映射并加一。当一个节点,不存在图中时,将其从hashmap中删除,并将对应的映射值,存入arraylist中。

  两个静态数组都是大小为nodesize的二维数组,(节点查找使用映射值)一个存储的是当前图内的点的联通情况(权重为1),另一个存储的是对联通性矩阵进行floyd运算后的矩阵。

3、第三次作业

  本次作业,对nodesize要求更改,并且添加了新的需求,联通块数量计算,最少票价计算,最少换乘次数计算,最少不满意度计算。

  首先,nodesize的更改,由于我没有使用magic number(上一次作业的教训),直接改动nodesize即可。

  此外,分析发现,新的需求中,联通块计算可以通过并查集实现,我增加了并查集方面的方法。

  而剩下的三个需求,其实可以和第二次作业中的最短路径一起归纳为图的权重问题。我对第二次作业的floyd方法进行了重构,重构成了一个templatefloyd(c++课中的模板类思想),并又构建了5个二维矩阵,用来存储不同需求下的图的权重矩阵和floyd运算后的结果矩阵。

五、bug与修复

1、第一次作业

  未发现bug。

2、第二次作业

  本次作业中,我忽略了得到最短路径方法的jml规格中的描述:当fromnodeid == tonodeid时,最短路径为0 ,导致了大面积的wa。

3、第三次作业

  未发现bug。

六、心得体会

  首先,我深刻理解了这一单元最开始时,老师在课上反复强调的,只要严格按照jml来实现,就不会有bug。自己的bug也是没有完全按照jml的约束实现。

  然而,在jml的实现中,仅仅做到实现jml也是不足够的。我的第三次作业的强测有一个点过的特别危险,35s的时间limit,我花了34.6779s跑完了程序。诚然,我严格按照jml约束实现了,但我没有考虑到性能的优化。在jml的实现中,还要注意性能的优化。

北航oo作业第三单元小结的更多相关文章

  1. 北航oo作业第四单元小结

    1.总结本单元两次作业的架构设计 在我动手开始总结我的设计之前,我看了其他同学已经提交在班级群里的博客,不禁汗颜,我是真的偷懒.其他同学大多使用了新建一个类,用以储存每一个UMLelemet元素的具体 ...

  2. 北航OO(2020)第三单元博客作业

    一.JML理论基础及相关工具链 1.JML理论基础 该部分梳理本单元作业中涉及到的JML知识. 1.1注释结构 JML采用javadoc注释的方式来表示规格,且每行以@开头.通过使用//@annota ...

  3. OO作业第三单元总结

    目录 一.JML语言理论基础及应用工具链 二.部署JMLUnitNG,自动生成测试用例 三.架构设计 第一次作业 第二次作业 第三次作业 四.Bug分析 五.心得体会 一.JML语言理论基础及应用工具 ...

  4. 北航oo作业第一单元小结

    前言 在经过了三次艰辛的oo作业后,oo课程的第一单元告一段落,这一单元,我作为一个oo小白,开始了解oo的编程思想,也有了自己的一点心得体会.把笔粗成字,不当之处,还请各位大佬多多指教. 一.分析程 ...

  5. BUAA OO 2019 第三单元作业总结

    目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...

  6. 北航OO(2020)第四单元博客作业暨学期总结

    一.第四单元架构设计 1.第一次作业 我在本次作业中设置了多个储存结构:Directory,ElementsInName,ElementsInId,Cache. Directory: 顾名思义,这是个 ...

  7. OO第三单元小结

    目录 JML理论基础 JML工具链 openjml使用 openjml总结 jmlunitng使用 代码分析 第一次作业 第二次作业 第三次作业 测试&bug分析 黑盒测试 白盒测试(Juni ...

  8. OO第三次博客作业--第三单元总结

    一.JML 语言的理论基础及应用工具链 JML 是一种行为接口规格语言,提供了对方法和类型的规格定义手段.通过 JML 和其支持工具,不仅可以基于规格自动构造测试用例,并整合了 SMT Solver ...

  9. OO课第三单元总结

    一.梳理JML语言的理论基础 (1)理论基础 JMl的出现很大程度上一为了行为接口的规范化,用这种语言来指定特定模块的特定功能.JML的核心部分分为三个部分:前置条件(requires).后置条件(e ...

随机推荐

  1. 菜鸟学Nhibernate 之路---(1)

    首先说一下我为什么要学这个Nhibernate,现在在公司做项目后台的逻辑层都是用动软生成的简单三层,搞来搞去都是这些东西,代码冗余量很大,每个类方法基本上都一样,真是纯正的码农,虽然后来我也尝试使用 ...

  2. [hdu3549]Flow Problem(最大流模板题)

    解题关键:使用的挑战程序设计竞赛上的模板,第一道网络流题目,效率比较低,且用不习惯的vector来建图. 看到网上其他人说此题有重边,需要注意下,此问题只在邻接矩阵建图时会出问题,邻接表不会存在的,也 ...

  3. SM4算法的c++实现

    百度到的论文已给出算法. flag为1为解密,flag为0是加密. #include<bits/stdc++.h> using namespace std; typedef long lo ...

  4. hadoop自动安装脚本

    还不能实现完全自动安装,只能算半自动的. 进行交互主要障碍有两点: 1. ssh-keygen的时候需要点击回车. 2. passwd 需要设置密码  如果谁能解决以上两点,欢迎email给我. 另外 ...

  5. SPOJ-TTM To the moon

    一句话题意:写一个支持区间修改,区间求和的可持久化数据结构. 考虑使用主席树,然而,区间修改怎么办? 似乎有标记永久化的方法. 对于线段树上完全覆盖标记产生贡献的区间,我们直接打上一个$tag$,而对 ...

  6. svn的revert、checkout、clean up、setting

    svn revert 描述恢复所有对文件和目录的修改,并且解决所有的冲突状态. svn revert不会只是恢复工作拷贝中一个项目的内容,也包括了对属性修改的恢复.最终,你可以使用它来取消所有已经做过 ...

  7. Codeforces Round #523 (Div. 2)D(二分,多重集)

    #include<bits/stdc++.h>using namespace std;const long long N=1e5+5;const long long MOD=1e9+7;l ...

  8. mysql设置最大连接数量

    mysql>mysql -uuser -ppassword(命令行登录MySQL) mysql>show variables like 'max_connections';(查可以看当前的 ...

  9. uva 10817(数位dp)

    uva 10817(数位dp) 某校有m个教师和n个求职者,需讲授s个课程(1<=s<=8, 1<=m<=20, 1<=n<=100).已知每人的工资c(10000 ...

  10. puppet的一个Bug

    前篇文章写了使用puppet管理500多台服务器,当然只是一部分,最主要的还是puppet脚本的编写,这个我会在以后的文章中一点一点写出来. 今天要写的是puppet的一个bug,版本是puppet ...