【面向对象】第三单元作业总结

单元总述


这个单元分为三次作业,主要是给出了JML描述的规格,然后需要我们根据JML描述的规格来写出相应的程序模块。

JML语言的理论基础、应用工具链


语言基础

(部分内容参考于官网

JML全称Java Modeling Language,是一种行为接口规范语言,可用于指定Java模块的行为 它结合了Eiffel的契约方法设计 Larch系列接口规范语言的基于模型的规范方法,以及细化演算的一些元素 

JML是一种行为界面规范语言(BISL),它建立在落叶松方法 ,在APP [Rosenblum95]和Eiffel中找到在这种规范风格中,可以称为面向模型,指定方法或抽象数据类型的接口及其行为特别是JML建立在Leavens和其他人在Larch / C ++完成的工作之上 

方法或类型 的接口是从程序的其他部分使用它所需的信息。对于JML,这是调用方法或使用字段或类型所需的Java语法和类型信息。对于方法,接口包括诸如方法的名称,其修饰符(包括其可见性以及是否为最终),其参数数量,返回类型,可能抛出的异常等等。对于字段,接口包括其名称和类型及其修饰符。对于类型,接口包括其名称,修饰符,包,它是类还是接口,它的超类型,以及它声明和继承的字段和方法的接口。JML使用Java的语法指定所有这些接口信息。

常见的JML工具

以下是Common JML发行版中每个工具的unix介绍页。每个手册页都有一些关于如何使用该工具的信息,并指定它们的选项和参数。

  • jml-launcher(图形用户界面工具的启动器)。
  • jml和jml-gui(检查器)。
  • jmlc和jmlc-gui(编译用于运行时断言检查)。
  • jmldoc和jmldoc-gui (包含JML规范信息的javadoc版本)。
  • jmle (编译用于执行或原型规范)。
  • jmlrac(java的一个版本,VM,包含CLASSPATH中的bin / jmlruntime.jar文件,用于运行使用jmlc编译的文件)。
  • jmlre(java的一个版本,VM,包括执行规范所需的运行时支持,用于运行使用jmle编译的文件 )。
  • jmlspec和jmlspec-gui (从Java源文件生成框架规范文件)。
  • jmlunit和jmlunit-gui (生成用于JUnit的单元测试代码存根 )。
  • jtest (结合了jmlc和 jmlunit的工作
  • jml-junit(JUnit的swing用户界面的一个版本,包括CLASSPATH中的bin / jmlruntime.jar和bin / jmljunitruntime.jar文件,用于对使用jmlc编译的文件和jmlunit生成的测试用例运行基于JML和JUnit的测试)。

部署SMT Solver

在辗转IJ和Eclipse反复安装OpenJML工具并对自己的代码进行分析后,我仍然是无法得到一份比较完整的测试结果。很可惜网上关于OpenJML的资料实在是有些少得可怜,而OpenJML的一些报错也实在是令人摸不着头脑。

就目前已经探索出来的一些结果而言,在windows10环境下,IntelliJIdea 2019.3版本下我们可以选取OpenJML中0.8.42版本中z3-4.7.1的Solver进行分析,其中z3-4.3.2不适用于win10系统,但是z3-4.7.1会报一些无法生成断言(检测变量)的错误,至今仍没有解决问题的头绪。

这里贴出对第一次作业中MyPath的检测结果

public /*@pure@*/ boolean containsNode(int node)


C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:28: 警告: The prover cannot establish an assertion (PossiblyNegativeIndex) in method containsNode
            if (this.node[i] == node) {
                         ^
C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:32: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:24: 注: ) in method containsNode
        return false;
        ^
C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:24: 警告: Associated declaration: C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:32: 注: 
    //@ ensures \result == (\exists int i; 0 <= i && i < nodes.length; nodes[i] == node);
 public boolean equals(Object obj)
 
 

C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:78: 警告: The prover cannot establish an assertion (PossiblyNegativeIndex) in method equals
            if (node[i] != ((Test) obj).getNode(i)) {
                    ^
C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:82: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:57: 注: ) in method equals
        return true;
        ^
C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:57: 警告: Associated declaration: C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:82: 注: 
      @ ensures \result == (\forall int i; 0 <= i && i < nodes.length;
        ^
C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:74: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\APP\OpenJML\openjml-0.8.42-20190401\openjml.jar(specs/java/lang/Object.jml):76: 注: ) in method equals
        if (node.length != ((Test) obj).size()) {
                                            ^
public /*@pure@*/ int getNode(int index)
 
 

C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:21: 警告: The prover cannot establish an assertion (PossiblyTooLargeIndex) in method getNode
        return node[index];
                   ^
C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:21: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Ryanw\IdeaProjects\homework9\src\Test.java:15: 注: ) in method getNode
        return node[index];

部署JMLUnitNG/JMLUnit

我们选择了比较简单的Path类来进行测试:

生成相应的文件树:

生成相应的测试结果:

[TestNG] Running:
  Command line suite

Passed: racEnabled()
Failed: constructor Path(null)
Passed: constructor Path({})
Failed: <<homework9.Path@1>>.compareTo(null)
Passed: <<homework9.Path@1>>.containsNode(-2147483648)
Passed: <<homework9.Path@1>>.containsNode(0)
Passed: <<homework9.Path@1>>.containsNode(2147483647)
Passed: <<homework9.Path@1>>.equals(null)
Passed: <<homework9.Path@1>>.equals(java.lang.Object@1c2c22f3)
Passed: <<homework9.Path@1>>.getDistinctNodeCount()
Failed: <<homework9.Path@1>>.getNode(-2147483648)
Failed: <<homework9.Path@1>>.getNode(0)
Failed: <<homework9.Path@1>>.getNode(2147483647)
Passed: <<homework9.Path@1>>.isValid()
Passed: <<homework9.Path@1>>.iterator()
Passed: <<homework9.Path@1>>.size()

===============================================
Command line suite

# Total tests run: 16, Failures: 5, Skips: 0
===============================================

架构设计

这三次作业是在整个作业过程中做得最为艰辛的三次作业。因为每次都因为各种各样的原因进行重构。首先在第一次作业中采用了数组的格式进行对数据的存储,第二次作业由于第一次作业的TLE进行重构改成了图的结构进行存储。在第二次作业中采用图的格式来进行对图结构的存储,并完成最短路径的计算,结果是使用十分不方便,并且由于数据结构的过于复杂,没有一个比较好的封装,导致了在设计算法的时候出现了问题(问题应该还是太过自信写了个自己眼中的并不正确的Dij)。第三次作业中整体重构了整个的数据结构。采用在Path阶段采用hashMap进行存储,而在生成图的时候生成一张由数组存储的邻接表矩阵,由此来避免算法出现的问题。

bug和修复情况

这次作业中主要的bug都出现在数据结构与针对数据结构的算法中。在第二次作业刚刚开始的时候使用到了Dijsktra算法来实现两点之间最短距离的计算,但是遗憾的是在写这个算法的时候出现了一些问题,导致后两次作业体验极差,几乎在de算法的bug。好在在最后一次作业中对中测第二组数据的测试过程中发现了这个bug并进行了改正。

对规格的心得体会

其实三次作业加两次实验做下来只是对JML有了一个基本的认识。运用了JML之后可能确实对每一种方法的描述更为精确了,毕竟个人感受JML几乎是一种数学语言的表达方式。但是这种表达方式既不接近我们平时的语言表达习惯,又不接近我们写程序的时候的思维习惯。几乎规格是独立于这两者之外的另外一种表达模式。甚至在我们进行第三次作业的时候出现了原来的JML规格不满足需求描述的情况。因此是否有必要为了程序的精确性,在需求与coding中间,引入另一个更可能出现问题的规格,在这里我持怀疑态度。不知道更好的解决方法是不是将需求用更规范的语言表达出来。但是JML的优点可能是JML提供了一套完整的从规格到代码的验证方法。总之,我们必须承认JML是一种避免程序出现问题的必要手段,但是希望有更好的从需求到规格的描述方法。

猜你喜欢

转载自www.cnblogs.com/Ryan16231112/p/10897616.html