OO第三单元作业总结
OO第三单元作业总结——JML
第三单元的主题是JML规格的学习,其中的三次作业也是围绕JML规格的实现所展开的(虽然感觉作业中最难的还是如何正确适用数据结构以及如何正确地对于时间复杂度进行优化)。
关于JML语言
JML语言概述
JML是Java Modeling Language的缩写,意思是Java建模语言,是一种进行详细设计的符号语言。
使用JML语言的好处主要有以下几点:
- 能够描述类和方法的运行方式,从而使代码的编写过程更加契合面向对象思想;
- 可以更加高效地发现和修正程序中的bug
- 在程序开发中降低bug的出现几率并及时发现已有的bug
所以说,JML对于面向对象的学习还是有很大的帮助的。
JML基本语法
下面总结一下目前JML学习中使用到的常用语法:
JML表达式
原子表达式:
\result表达式:表示方法执行后的返回值。\old( expr )表达式:用来表示一个表达式expr在相应方法执行前的取值。量化表达式:
\forall表达式:全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束。例如(\forall int i,j; 0 <= i && i < j && j < 10; a[i] < a[j])\exists表达式:存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束。例如(\exists int i; 0 <= i && i < 10; a[i] < 0)\sum表达式:返回给定范围内的表达式的和。例如,(\sum int i; 0 <= i && i < 5; i)此外,还有集合表达式、包含操作符的表达式等。
方法规格
前置条件:通过
requires子句来表示;后置条件:通过
ensures子句来表示;副作用范围限定:通过使用关键词
assignable或者modifiable限定,其中assignable表示可赋值,而modifiable则表示可修改;异常区分:使用
signals子句,signals子句的结构为signals (Exception e) b_expr,表示当b_expr为 true 时,方法会抛出括号中给出的相应异常e。
类型规格
- 不变式
invariant:不变式是要求在所有可见状态下都必须满足的特性,语法上定义invariant P; - 状态变化约束
constraint:用constraint来对前序可见状态和当前可见状态的关系进行约束。
- 不变式
JML应用工具链
- OpenJML:检查JML的语法和逻辑。
- JMLUnit/JMLUnitNG:根据JML自动生成测试样例。
部署SMT Solver
在多次尝试试用各种方式安装openJML后,终于可以基本对于程序使用SMT Solver进行测试。
测试命令(windows环境):
java -jar path1\openjml.jar -check path2\classname.java
(其中,path1为openjml解压到的文件夹,path2位需进行测试的java程序所在的位置)
最开始,我先对于OpenJML网站上的最简单的程序进行了测试,代码如下:
public class MaybeAdd {
//@ requires a > 0;
//@ requires b > 0;
//@ ensures \result == a+b;
public static int add(int a, int b){
return a-b;
}
public static void main(String args[]){
System.out.println(add(2,3));
}
}
测试并没有报出错误,为了检测这种测试方法的正确性,我改了原代码中requires中的==,将其改为了=,再次进行测试:
public class MaybeAdd {
//@ requires a > 0;
//@ requires b > 0;
//@ ensures \result = a+b; //此处发生改变
public static int add(int a, int b){
return a-b;
}
public static void main(String args[]){
System.out.println(add(2,3));
}
}
此次,测试报出两个错误,表明等号位置发生错误:

由于使用SMT Solver测试经常出现一些不可知的错误,所以这回我只选用了一个MyPath类中非常简单的方法进行了测试:
public class GetNode {
private /*@spec_public@*/ int[] nodes;
/*@ requires index >= 0 && index < nodes.length;
@ assignable \nothing;
@ ensures \result == nodes[index];
@*/
public int getNode(int index) {
return nodes[index];
}
}
测试没有报错,表示程序正确。
此时改变代码中的nodes.length为nodes.size():
public class GetNode {
private /*@spec_public@*/ int[] nodes;
/*@ requires index >= 0 && index < nodes.size();
@ assignable \nothing;
@ ensures \result == nodes[index];
@*/
public int getNode(int index) {
return nodes[index];
}
}
测试报出一个错误,如下图所示:

部署JMLUnitNG/JMLUnit
由于之前的代码的jml规格中存在不少问题,所以这回我还是使用官网给出的简易demo先进行测试:
public class MaybeAdd {
//@ requires a > 0;
//@ requires b > 0;
//@ ensures \result == a+b;
public static int add(int a, int b){
return a-b;
}
public static void main(String args[]){
System.out.println(add(2,3));
}
}
测试命令与SMT Solver类似:
java -jar path1\jmlunitng.jar path2\classname.java
最终产生的测试文件如下图:

同样,对于MyPath类中getNode方法进行生成测试文件:
public class GetNode {
private /*@spec_public@*/ int[] nodes;
/*@ requires index >= 0 && index < nodes.length;
@ assignable \nothing;
@ ensures \result == nodes[index];
@*/
public int getNode(int index) {
return nodes[index];
}
}
最终生成的测试文件如下:

梳理架构设计与BUG分析
这个单元的作业可以说是至今为止最差的几次,虽然在JML的理解上是没有出现什么问题的,但是由于数据结构上使用的错误,以及算法优化的问题,导致在代码的实现方面出现了很大的问题。
第一次作业
- 类图

这次的架构基本就是按照指导书的要求写的,分为了Main,Mypath和MyPathContainer三个类。
- 主要度量图


从度量图中可以看出,由于第一次作业较为简单,所以每个类和方法的复杂度都还是比较低的。
bug分析
这单元第一次作业其实非常简单,但是需要考虑的方面还是比较多的。一方面是对于数据容器的选择,在这方面我使用的是hashmap,可以在查找时尽量保证复杂度为O(1)。另一方面是如何分配操作的位置,在这一方面我栽了跟头,没能注意到加减道路的指令比查不同点的数目的指令的数量少的多,所以可以将找不同点的数目这一运算分散到加减路径的操作中,而这个问题也使我在强测中TLE了不少点。
修改方法:
使用一个hashset进行点的储存,可以直接防止重复加点,并且将加点操作分散到加减路径中,代码修改即为:
public int getDistinctNodeCount() {
return nlist.size();
}
第二次作业
- 类图

- 主要度量图


bug分析
在这一次作业中,我犯了一个致命性的错误,在算法的选择上没有清晰的认识,导致自己没有用现成的算法,而是使用了自己所想的龟速算法,每次查找都遍历了所有的边,导致TLE成为了必然。在bug修复中,我将算法改为了dijkstra算法,结果轻松地过了之前TLE的点。(上面的图为修改后代码的类图和主要度量图)
第三次作业
- 类图

本次的架构是沿用上次的作业,使用dijkastra算法,并将四种查找综合为同一种,都当作为求最小权值的路径。
- 主要度量图


bug分析
自己的bug:
这次作业我因为使用了不正确的拆点法而死的很惨。其实在最初写代码的时候,我已经意识到用我所想到的拆点法会需要比较大的数组,但是由于我想当然地以为测评机是实现很多如此大的数组,这点并没有引起我的注意,结果是我太天真,最终由于RE,又没有多少时间进行重构,导致最后只能改小数组来通过中测,但是这也使我强测发生了爆栈的问题。
最后在bug修复的时候,我改了一种方法,将拆点法改为了不拆点的方法,并借鉴讨论区大佬和身边大佬的方法,将同一条路径中的点两两相连,这样它们之间的权值就可以直接加上换乘时需多加的权值,之后再进行dij算法查找最小权值的边,最后结果在减去各个情况换乘需加上的权值(因为之前都加了一遍)。这种方法可以完美避开了使用dij算法时易出现的找不到最优解的情况。
他人的bug:
在测试他人的bug,发现大家主要错的还是两点:一种情况是算法不够优化,速度过慢导致TLE;另一种情况是在查找最小权值路径时,发生了隐形的错误,导致最后的结果不是最终情况。
对规格撰写和理解上的心得体会
这三次作业的理解和完成虽然并不是非常顺利,在数据结构和算法的使用上遇到了一些瓶颈,但是可以肯定的是,对于jml语言已经初步入门,能够基本地根据方法编写相应的JML规格和理解现有的JML规格。根据JML规格编写代码,我也体验到了真正面向对象编写程序的过程。虽然目前写的程序规模还比较小,JML还没有体现出很大的作用,但是当之后的代码量大的时候,使用JML可以使我们更快地定位到错误的地方,这就能对我这个经常debug无能的人提供很大的帮助。
OO第三单元作业总结的更多相关文章
- 【OO学习】OO第三单元作业总结
[OO学习]OO第三单元作业总结 第三单元,我们学习了JML语言,用来进行形式化设计.本单元包括三次作业,通过给定的JML来实行了一个对路径的管理系统,最后完成了一个地铁系统,来管理不同的线路,求得关 ...
- OO第三单元作业——魔教规格
OO第三单元作业--魔教规格 JML的理论基础和相关工具 JML(Java Modeling Language,Java建模语言),在Java代码种增加了一些符号,这些符号用来标志一个方法是干什么 ...
- OO第三单元作业(JML)总结
OO第三单元作业(JML)总结 目录 OO第三单元作业(JML)总结 JML语言知识梳理 使用jml的目的 jml注释结构 jml表达式 方法规格 类型规格 SMT Solver 部署JMLUnitN ...
- OO第三单元作业小结
一.JML理论基础及应用工具链情况 理论基础 1.JML表达式 \result:表示方法执行后的返回值. \old(expr):表示一个表达式expr在相应方法执行前的取值. \foall:全称量词修 ...
- 2019北航OO第三单元作业总结
1.梳理JML语言的理论基础.应用工具链情况 JML基础理论: JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言.JML是一种行为接口规格语言,基 ...
- 北航OO第三单元作业总结(3.1~3.3)
JML简介及相关工具链使用 1.JML规格描述语言介绍 本单元学习的内容是JML规格描述语言.我们知道,面向对象方法是一个抽象过程,需求者仅需关注方法的规格.规格是对一个方法/类/程序的外部可感知行为 ...
- OO第三单元作业分析
一.JML的理论基础应用工具链 JML是用于对Java程序进行规格化设计的一种表示语言.基于Larch方法构建. (1)注释 JML以javadoc注释的方式来表示规格,每行都以@起头.有两种注释方式 ...
- BUAA OO 2019 第三单元作业总结
目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...
- 规格化设计——OO第三单元总结
规格化设计--OO第三单元总结 一.JML语言理论基础.应用工具链 1.1 JML语言 JML(java modeling language)是一种描述代码行为的语言,包括前置条件.副作用等等.J ...
随机推荐
- 冰多多团队alpha阶段发布说明
标题:冰多多Alpha阶段发布说明 Alpha版本功能介绍 我们项目当前是两个部分,前端编辑器和后端mtermux是分开的,是两个独立的app项目,还没有完美的连起来(我们alpha阶段目标任务是不必 ...
- 《Maven实战》整理
一.maven介绍 Maven是优秀的构建工具,能够帮我们自动化构建过程,从清理.编译.测试到生成报告,再到打包和部署. Maven能帮助我们标准化构建过程.在Maven之前,十个项目可能有十种构建方 ...
- python 获取天气信息,并绘制曲线
import urllib.request import gzip import json print('------天气查询------') def get_weather_data() : cit ...
- Server Tomcat v8.5 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
Server Tomcat v9.0 Server at localhost was unable to start within 45 seconds. If the server requires ...
- 【java/oralce/sql】往一张仅有id,名称,创建时间三个字段的表中插入百万数据需要多久?1分26秒
代码下载:https://files.cnblogs.com/files/xiandedanteng/fastfilltable20191222.rar 表testtb18的结构如下: CREATE ...
- 认真分析mmap:是什么 为什么 怎么用(转)
阅读目录 mmap基础概念 mmap内存映射原理 mmap和常规文件操作的区别 mmap优点总结 mmap相关函数 mmap使用细节 回到顶部 mmap基础概念 mmap是一种内存映射文件的方法,即将 ...
- Xamarin图表开发基础教程(13)OxyPlot框架支持的其它图表
Xamarin图表开发基础教程(13)OxyPlot框架支持的其它图表 除了以上提到的图表外,OxyPlot组件还包含了6种类型的其它图表,分别为等高线图.箱线图.饼图.热图.散点图和散点误差图,如图 ...
- jstl标签库使用报错index_jsp.java找不到问题
初学jstl的时候记得只需要讲jstl和standard的jar放在lib下面,然后jsp中使用对应导入语法就可以使用标签库了. 但那时候用的是myeclipes,myeclipes的导包的过程记得是 ...
- Python 精选文章
操作Excel,通过宏调用Pyhton(VBA调Python) 第一个django项 https://www.jianshu.com/p/45b07d8cd819
- 【iCore4 双核心板_FPGA】实验二十:NIOS II之UART串口通信实验
实验指导书及源代码下载地址: 链接:https://pan.baidu.com/s/1g_tWYYJxh4EgiGvlfkVu1Q 提取码:dwwa 复制这段内容后打开百度网盘手机App,操作更方便哦 ...