OO第三单元总结

OO第三单元总结

一.JML语言的理论基础与应用工具链

1.理论基础

注释

​ 行注释://@annotation

​ 块注释:/* @ annotation @*/

表达式

​ \result表达式:表示一个非 void 类型的方法执行所获得的结果,即方法执行后的返回值

​ \old( expr )表达式:用来表示一个表达式 expr 在相应方法执行前的取值

​ \not_assigned(x,y,...)表达式:用来表示括号中的变量是否在方法执行过程中被赋值

​ \not_modified(x,y,...)表达式:限制括号中的变量在方法执行期间的取 值未发生变化

​ \nonnullelements( container )表达式:表示 container 对象中存储的对象不会有 null

​ \type(type)表达式:返回类型type对应的类型(Class)

​ \forall表达式:全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束

​ \exists表达式:存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束

​ \sum表达式:返回给定范围内的表达式的和。

​ \product表达式:返回给定范围内的表达式的连乘结果

​ \max表达式:返回给定范围内的表达式的最大值

​ \min表达式:返回给定范围内的表达式的最小值

​ \num_of表达式:返回指定变量中满足相应条件的取值个数

方法规格

​ 前置条件(pre-condition):requires P;要求调用者确保P为 真

​ 后置条件(post-condition): ensures P;方法实现者确保方法执 行返回结果一定满足谓词P的要求,即确保P为真

​ 副作用范围限定(side-effects):使用关键词 assignable 或者 modifiable ,assignble 表示可赋值,而 modifiable 则表示可修改

​ signals子句: signals (Exception e) b_expr ,当 b_expr 为 true 时,方法会抛出括号中给出的相应异常e

类型规格

​ 不变式invariant : invariant P, 要求在所有可见状态下都必须满足特性P

​ 状态变化约束constraint :对前序可见状态和当前可见状态的关系进行约束

2.应用工具链

OpenJML:用于检查JML语法规范

SMT Solver:根据规格判断程序的正确性

JMLUnitNG:自动生成测试样例进行单元测试

二.部署使用JMLUnitNG

这里使用自己的类和方法

public class Demo2 {
    /*@
      @ public normal_behaviour
      @ requires x > 0 && y > 0;
    */
    public static int product(int x, int y) {
        return x * y;
    }
	public static void main(String[] args) {
    	product(-45, -5);
	}
}

将jmlunitng.jar和Demo2.java放在同一文件夹,openjml.jar在另一文件夹

使用git bash执行指令

最后结果

可以看出,对于x<0,y<0,以及溢出的样例出现Failed报错

三.架构设计

第一次作业

在MyPath类中建立一个HashSet set用于存放路径中的结点便于查询

在MyPathContainer中建立HashMap<Integer, Path> idToPath和HashMap<Path, Integer> pathToId双映射,便于根据id查找路径和根据路径查找id,同时也建立一个HashSet arr存放结点

第二次作业

第二次作业要将Path集合存成无向图,计算两个结点之间的最短路,以及判断连通性。首先设立一个新类Nodes表示一组点对,然后建立HashSet edges 存放边,HashMap<Nodes, Integer> shpath存放算得的两点间最短路。最短路算法采用bfs,初始化时将edges中的Nodes权值设1,其余设max,每次算单源最短路存放在shpath中,找到最短路则联通。

第三次作业

这次作业新增最少换乘,最少票价,最少不满意度的计算,以及统计连通块个数。统计连通块采用并查集的方法,使用HashMap<Integer, Integer> pre保存每个结点的起始结点,再借助join和find方法找到并合并起始结点。三个计算本质上也是找最短路,但是需要重新构图,即将每条Path的任意两个结点相连,最少换乘图权值都为1,最少票价图权值为两点间最短路加2,最少不满意度图权值为两点间最少不满意度加32,将这些权值存在HashMap<Nodes, int[]> newedges中,然后据此用dijstra算出最短路存进transfergraph,pricegraph,unpleasantgraph。

四.bug和修复

第一次作业cpu超时了,原因是采取ArrayList存点,每次读指令都会计算一次,改成HashMap存储以及将计算放在写指令中就能解决问题。

第二次作业还是CTLE。每次访问点对都会新建对象,且每次构图都会建立一个大矩阵,这时使用floyd算图就会消耗很多时间,因为有很多无用计算,改为dijstra就能减少无用计算量,节省时间。

第三次作业算不满意度报WA,检查发现之前算得的最少不满意度会影响后面的不满意度计算,即此图没有最优子结构,因此每次计算不满意度时清空原来的图就能保证正确性。

五.心得体会

JML规范化语言初看是很繁琐冗长的,让人没有学习的欲望,但在根据规格写代码做作业的时候可以发现写代码变得很容易,只要按着规格的描述一步步去实现即可,而且只要规格正确就能保证正确性。事实上这也正体现规格和自然语言的差异,我们以前拿到的需求都是简单直白的,一看就知道要什么,但真正实现的时候却发现其实并不知道该怎么做,而规格虽然”麻烦“,但完全理解后却能对需求有更准确更有目的性的认识。

但不能否认的是JML真的难写,用OpenJML跑课程代码都能找到很多语法错误。。另外不能只看规格死写程序,OO还是需要数据结构的,有一个好的架构和合适的数据结构是有很大帮助的,这能帮助我们理解程序应该做什么,我们应该做什么,层次明晰了也许就不会出现大片的CTLE。

posted on 2019-05-22 21:29  ture117  阅读(97)  评论(0编辑  收藏  举报

导航