一、梳理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. service使用handler与Activity沟通的两种方法

    通过之前的学习,我们知道了在主线程中声明一个handler实例并实现了消息的处理方法之后,我可以在子线程中用此实例向主线程发消息,在处理方法中获取消息并更新UI. 那么,如果我们想用handler在s ...

  2. npm设置代理提高下载速度

    *nix上给网络类程序设置代理的通用办法,即导出http_proxy/https_proxy环境变量对npm不起作用 需要用npm自己的配置命令来解决: npm set proxy $PROXY np ...

  3. Sublime Text 3下安装Emmet的问题

    电脑装了Sublime Text 3,顺便安装了很多插件,今天编写前端HTML代码时,想用起前端常用的Emmet插件的功能,Emmet插件已经安装好了,奈何输入简写格式,按“CTRL+E”,没有反应. ...

  4. vivado中使用debug不能连接到vcse_server

    打开 Xilinx Design Tools -> ISE Design Suite 14.7 -> Accessories -> ISE Design Suite 64 Bit C ...

  5. 第一个 Django 应用

    1. 创建项目 1.1 新建项目 首先新建一个项目,名为 mysite,命令如下: django-admin startproject mysite # 或用 django-admin.py 运行成功 ...

  6. Tomcat之NIO 启动与应用分析

    概述 从入门Web开始一直在使用Tomcat,随着对网络相关的知识的进一步了解,觉得越有必有去阅读一下常用的开源服务器的整个工作流程,以及使用场景,对比几款服务器的优劣势.最终根据合适的业务场景进行优 ...

  7. 【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)

    [分析]浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang) 今天无意中看到有关Invoke和BeginInvoke的一些资料,不太清楚它们之间 ...

  8. Ocelot(三)- 服务发现

    Ocelot(三)- 服务发现 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/10907856.html 源码地址:https ...

  9. 【转载】【爬坑记录】hyperledger caliper 性能测试工具使用的一些问题记录

    原文: https://blog.csdn.net/raogeeg/article/details/82752613 安装方法详见:https://github.com/hyperledger/cal ...

  10. pb_ds的优先队列实现dijkstra

    用pb_ds的优先队列来做dijkstra..据说noip能用哟. 先来篇关于仿函数的文章. 由于pb_ds支持由迭代器访问元素,并且push操作会返回一个迭代器,merge操作会更新迭代器,相当于帮 ...