2019北航oo课程第三单元作业总结..#_#..

  这三次作业明显和前两波作业不同,第一波作业带你理解面向过程与面向对象的不同,第二波作业让你理解什么是多面向,而第三波作业就是比较真实的东西了——jml。第三次作业通过阅读jml理解函数的作用,并想法设法完成jml所要求的任务。第三次作业对复杂度也有较高的要求,用普通的思路没有好好解决复杂度问题的话,强测往往会挂掉,因此第三次作业也不是单纯的看懂jml的作业,而是在理解了jml所要求的基础上尽力进行优化才是主旨。做完会发现,并不是按照jml一步步实现是好的选择,可以灵活运用其他方法和数据结构等综合起来之后能实现完整的jml所要求的功能才是好的选择。、

 <1>JML语言

1.1jml语言概述

  JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言。JML是一种行为接口规格语言 (Behavior Interface Specification Language,BISL),基于Larch方法构建。BISL提供了对方法和类型的规格定义 手段。所谓接口即一个方法或类型外部可见的内容。JML主要由Leavens教授在Larch上的工作,并融入了Betrand Meyer, John Guttag等人关于Design by Contract的研究成果。近年来,JML持续受到关注,为严格的程序设计提供 了一套行之有效的方法。通过JML及其支持工具,不仅可以基于规格自动构造测试用例,并整合了SMT Solver等工具 以静态方式来检查代码实现对规格的满足情况。

  一般而言,JML有两种主要的用法:
  (1)开展规格化设计。这样交给代码实现人员的将不是可能带有内在模糊性的自然语言描述,而是逻辑严格的规 格。
  (2)针对已有的代码实现,书写其对应的规格,从而提高代码的可维护性。这在遗留代码的维护方面具有特别重要 的意义。

 

1.2JML基本语法

1.2.1原子表达式

\result : 方法执行的返回值

\old(expr) : 指expr在方法执行前的取值

\not_modify(x, y, ...) : 括号中得到变量在方法执行期间的取值未发生变化

等等。

 

1.2.2量化表达式

其中最常用的为这两个,也是这次作业遇到最多的。

\forall : 全称量词修饰的表达式。对于给定范围的元素,每个元素都满足约束条件,样例(\forall int i;  0 < i && i < 10; a[i] > 0)

\exists : 存在量词修饰的表达式。对于给定范围的元素,存在一个元素都满足约束条件,样例(\exists int i;  0 < i && i < 10; a[i] > 0)

 

1.2.3操作符

JML表达式中可以正常使用Java语言所定义的操作符,包括算术操作符、逻辑预算操作符等。此外,JML专门又定义 了如下四类操作符。

E1<:E2 : 若E1是E2的子类型,该表达式为真

a_expr <==> b_expr : 其中a_expr与b_expr均为布尔表达式,

意味a_expr == b_expr

a_expr <=!=> b_expr : 其中a_expr与b_expr均为布尔表达式,

意味a_expr != b_expr

a_expr ==> b_expr : 其中a_expr与b_expr均为布尔表达式,

当a_expr == false或a_expr == true && b_expr == true时,该表达式值为true

 

1.2.4方法规格

前置条件:前置条件通过requires子句来表示,例如requires P 。其中requires是JML关键词,表达的意思是“要求调用者确保P为真”。

后置条件:后置条件通过ensures子句来表示: ensures P。其中ensures是JML关键词,表达的意思是“方法实现者确保方法执行返回结果一定满足谓词P的要求,即确保P为真”。

副作用范围限定:副作用指方法在执行过程中会修改对象的属性数据或者类的静态成员数据,从而给后续方法的执行带来影响。从方法规格的角度,必须要明确给出副作用范围。JML提供了副作用约束子句,使用关键词 assignable 或者modifiable 。

 

 <2>JML语言 

  在Windows PowerShell中执行指令“java -jar path\to\jmlunitng.jar path\to\Myproject\classname.java”

  编译测试用文件和MyPath文件,然后就可以进行对mypath测试的操作了。

  以下是对mypath文件的测试:

 

 

 

<3>架构设计和bug的修复情况

3.1 数据结构

3.1.1第一次作业

  在mypath中,我用的是int型数组。在myPathContainer中,第一次作业的数据结构刚开始我由于没有注意到复杂度的问题,因此刚开始我用arraylist来存取的每一个path,在解决每一个函数的时候都用遍历来解决问题,因此我的强测直接炸了。在修改的时候,我在pathcontainer直接改用了数据结构,把arraylist直接改成了hashmap,把id作为key,path作为内容。另外为了解决容器内所有不同节点的问题又新建了了一个hashmap用来存所有不一样的结点。

 

3.1.2第二次作业

  在mypath中,我用的还是int型数组,几乎没有改动。mygraph中,作业一中的所有数据结构都保留了,只不过多有用了两个二维数组来作者邻接矩阵来存图,还多了一个hashmap用来发配给每一个结点名字。

 

3.1.3第三次作业

  mypath还是没有变化。myrailwaysystem中, 作业二中的所有东西都保留了,其中多设置了三个类分别来解决最少转换次数,最少票价,最少不满意度的问题。这三个类中分别保存着图,图也用邻接矩阵来存,也分别都有hashmap来分配名字,图的构建方式差不多,但是边的权值的设置都不一样。

 

3.2实现方法

3.2.1第一次作业

  刚开始用的artaylist来解决的问题,那自然比如说解决容器内不同的节点个数的时候,自然用的就是遍历法来解决,然后强测炸了。于是后来用的hashmap来存取一切数据,并且新建了一个hashmap用来存取不同节点,key为节点的数,内容为结该点的个数,这样在addpath和removepath的时候直接维护这个hashmap,在求不同节点个数的时候直接把这个hashmap的key的个数输出就可以了。

 

3.2.2第二次作业

  保留了第一次的所有的数据结构和方法。在第二次作业中我用的邻接矩阵来存的图,有一个矩阵来存取两个结点之间是否有边,每加进来发现有边则++一下,用这个邻接矩阵来维护另一个矩阵,这个矩阵是用来存取结点之间的距离,在每一次addpath和removepath的时候重新维护一下这个矩阵,并进行Floyd算法就可以把节点之间的最短距离给算出来。

 

3.2.3第三次作业

  同样保留了第二次作业的所有的数据结构和方法,这回为了完成最少票价最小不满意度和最少换成,要分别建图。这三个图采用的都是同点分离的方法,在不同路径上的相同点起不一样的名字,并给所有的这些点一个总点,总点与这些分点到相连。最小票价时分点到总点边长为2,路径中的边长为1,总点到分点边长为0。不满意度时分点到总点为32,路径中边长是公式的值,总点到分点的边长为零。最小换乘时分点到总点为1,路径中边长为0,分点到总点的边长为0。这样就建好了三个图,在每一次有新的输入的时候都要分别重新建好这三个图。在要求相应的值的时候,得到输入的起点和重点,因为这回应用的是迪杰斯特拉算法,因此只需要用起点跑一遍,并记下该起点所跑的结果,为以后没准用到做准备。

 

3.3 bug的修复情况

  由于在写之前和宿友交流的比较深刻,有了他人的前车之鉴,因此在写完之后在方法上并没有太大的bug。但是还是有一些细节的地方出现了一些问题,原因是我并没有把整个jml完整的进行理解,而是东凑一块西凑一块,于是完成之后会有一些判断条件没有判断,或者是写了许多多于代码等。因此要通读jml之后整体的去感受它,了解数据进来到操作到输出的一条龙整个行程到底是怎么样的。

 

<4>心得体会

  本次作业虽然没有学习像第一次作业那样的对于面向对象的理解,没有学习像第二次作业的对于多线程的新知识,但是学习了十分使用的工具jml。也许相对来说没有那么硬核,但是确实给我们带来了学多意外的知识。除了对于jml的理解,当我们真正尝试去完成jml所要求的任务时便可感受到其实他只是规定了开头和结局和一些变量的控制,它的实现方法是可以靠我们随意发挥得。没做作业之前还以为只要一步一步完成就可以了,是个极其简单的任务,但是意外地用到了许多我没有接触到过的数据结构和算法,是我们做作业以来第一次对算法的要求那么高的一次。不同水平的人,拿到了一样的jml却有天地的性能差别也是有可能的。这次作业让我感觉对与工程化的写代码工作又有了新的认识,感谢老师和助教们对这次作业的设计。

 

 

 

 

posted @ 2019-05-22 20:31  yupobo  阅读(151)  评论(0编辑  收藏  举报