• OO第三单元总结


    这一单元,主要考察了对JML的理解,以及各种容器的选择以及数据结构相关知识。

    一、JML的理论基础和相关规范

    JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言。告诉编程者函数的具体功能是什么,相比文字描述而言,更具有逻辑性。同时他是一种规范的统一的规格语言,能够让阅读代码的人快速的理解,不存在歧义。

    1、注释结构

    requires子句定义该方法的前置条件(precondition)。

    assignable列出这个方法能够修改的类成员属性, othing是个关键词,表示这个方法不对任何成员属性进行修改,所以是一个pure方法。

    ensures子句定义了后置条件。

    2、JML表达式

    (1)原子表达式

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

    old( expr )表达式:用来表示一个表达式 expr 在相应方法执行前的取值。主要用于评估 expr中的对象是否发生变化。

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

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

    (2)量化表达式

    forall表达式:全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束。e.g. (forall int i,j; 0 <= i && i < j && j < 10; a[i] < a[j])

    exists表达式:存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束。e.g.(exists int i; 0 <= i && i < 10; a[i] < 0)

    sum表达式:返回给定范围内的表达式的和。e.g. (sum int i; 0 <= i && i < 5; i) ,

    product表达式:返回给定范围内的表达式的连乘结果。 e.g.(product int i; 0 < i && i < 5; i)

    max表达式:返回给定范围内的表达式的最大值。e.g. (max int i; 0 <= i && i < 5; i)

    min表达式:返回给定范围内的表达式的最小值。e.g. (min int i; 0 <= i && i < 5; i)

    (3)集合表达式

    集合构造表达式:可以在JML规格中构造一个局部的集合(容器),明确集合中可以包含的元素。 new JMLObjectSet {Integer i | s.contains(i) && 0 < i.intValue() } 表示构造一个JMLObjectSet对象,其中包含的元素类型为Integer,该集合中的所有元素都在容器集合s中出现

    (4)操作符

    子类型关系操作符: E1<:E2 ,如果类型E1是类型E2的子类型(sub type),则该表达式的结果为真,否则为假。如果E1和E2是相同的类型,该表达式的结果也为真。
    等价关系操作符: b_expr1<==>b_expr2 或者b_expr1<=!=>b_expr2 ,其中b_expr1和b_expr2都是布尔表达式,这两个表达式的意思是b_expr1==b_expr2 或者b_expr1!=b_expr2 。
    推理操作符: b_expr1==>b_expr2 或者b_expr2<==b_expr1 。对于表达式b_expr1==>b_expr2而言,当b_expr1==false ,或者b_expr1==true 且b_expr2==true 时,整个表达式的值为true 。
    变量引用操作符:除了可以直接引用Java代码或者JML规格中定义的变量外,JML还提供了几个概括性的关键词来引用相关的变量。 othing指示一个空集;everything指示一个全集,即包括当前作用域下能够访问到的所有变量。

    3、方法规格

    前置约束:使用requires语句描述,表示方法执行的一些要求约束。

    后置条件:使用ensures语句描述,表示方法执行结果的一些约束。

    作用范围:使用assignable语句描述,表示方法可以修改的变量。

    对于前置条件与后置条件通常有两种类型,分别是正常执行 ormal_behavior和异常exception_behavior两种类型,对于异常行为的结果,通常使用signal语句描述。

    4、类型规格

    不变式:invariant要求所有在可见状态下都满足的条件。
    状态约束变量:constraint要求状态变化过程中满足的条件。

    5、JML工具链

    openjml是所有工具链的核心,可以通过命令行工具对代码进行jml的语法检查,代码静态推导和动态检查。

    JMLUnitNG/JMLUnit可以针对类自动生成测试样例并进行测试。

    二、部署JMLUnitNG并进行测试

    JMLUnitNG主要用来根据JML语言自动生成数据并进行测试。针对Group接口实现自动生成测试样例结果如下:

    [TestNG] Running:
      Command line suite
    
    Failed: racEnabled()
    Passed: constructor MyGroup(0)
    Passed: constructor MyGroup(-2147483648)
    Passed: constructor MyGroup(2147483647)
    Passed: <<MyGroup@6cec342d>>.addPerson(null)
    Passed: <<MyGroup@1ad708cb>>.addPerson(null)
    Passed: <<MyGroup@43e4567a>>.addPerson(null)
    Passed: <<MyGroup@80e4ebdd>>.addPerson(java.lang.Object@3db361f2)
    Passed: <<MyGroup@16e47edc>>.addPerson(java.lang.Object@7a52b631)
    Passed: <<MyGroup@4b14684d>>.addPerson(java.lang.Object@81a3b443)
    Passed: <<MyGroup@56c3a741>>.addrelation()
    Passed: <<MyGroup@28b4a9ed>>.addrelation()
    Passed: <<MyGroup@64d1a742>>.addrelation()
    
    ===============================================
    Command line suite
    Total tests run: 12, Failures: 0, Skips: 0
    ===============================================
    

    这些测试数据,可以测试边界情况,但是其他极端情况还是需要自己自动生成,感觉实际效果并没有想象中的好。

    三、架构设计

    按照作业梳理自己的架构设计,特别分析自己的模型构建策略

    第九次作业

    本次作业,需要完成的任务为实现 person 类和简单社交关系的模拟和查询,学习目标为JML规格入门级的理解和代码实现。

    唯一的难点在于isCircle,我采用的是BFS的方法,算是比较简单。

    有一个坑点是addRelation方法当id1 == id2 && contains(id1)时,不用进行任何操作,没有异常。

    第十次作业

    本次作业最终需要实现一个社交关系模拟系统。可以通过各类输入指令来进行数据的增删查改等交互。

    添加了 Group 接口,实现一些关于查询组内信息的方法。

    在Group里面的relationSum和 valueSum两个方法需要考虑到时间复杂度的问题,如果完全按照JML的规格会有O(n*n)的复杂度,导致CTLE。

    同时,Network里面也不能用ArrayList了,需要用HashMap来提升效率,可以减少contains+getID的时间复杂度。

    第十一次作业

    本次作业最终需要实现一个社交关系模拟系统。可以通过各类输入指令来进行数据的增删查改等交互。

    本次作业在上一次作业的基础上,考察了大量的数据结构的内容,主要是这些方法之中的核心为MinPath,StrongLinked,BlockSum这三个方法,分别考察的是最短路,点双连通,联通块的数量。分别对应的算法是Dijkstra,Tarjan,并查集。但是需要进行一下优化才能保证不超时。点双联通也可以使用遍历删点看是否联通的做法。

    四、BUG情况

    这一单元的作业真可谓是惨不忍睹。

    第一次因为没有看情况JML规格,addRelation方法当id1 == id2 && contains(id1)时的情况没有考虑,导致强测只有5分,没有进互测。

    第二次作业我暗下决心,一定要研读JML规格,一步步按照规格写,结果20个点全部CTLE爆零,同样没有进互测。

    第三次作业,我才明白过来,原来只需要看懂JML规格就行,如果完全按部就班反而没有啥好下场,考察的重点在于如何实现,需要选择合适的容器,最优的数据结构算法。最后还是幸运的进了互测,但在实现的性能上还是有不足,仍然有CTLE的bug需要修复。

    五、心得与体会

    这一单元真的是对我来说,如同过山车一般,经历了一次南辕北辙,两次重构。通过不断地学习与练习,可以更深层次的了解JML并进行代码的实现。希望下次好好做一下阅读理解吧,先搞清楚课程组想让我们做什么,再开干。

  • 相关阅读:
    [C#][Newtonsoft.Json] Newtonsoft.Json 序列化时的一些其它用法
    [C#] 获取计算机内部信息
    [Bug] 解决 Sql Server 数据库死锁问题
    Visual Studio提示“无法启动IIS Express Web服务器”的解决方法
    [svn] TortoiseSVN 图文操作
    [js] 如何 在 jQuery 中的 $.each 循环中使用 break 和 continue
    Redis 小白指南(三)- 事务、过期、消息通知、管道和优化内存空间
    Redis 小白指南(二)- 聊聊五大类型:字符串、散列、列表、集合和有序集合
    Redis 小白指南(一)- 简介、安装、GUI 和 C# 驱动介绍
    Redis 小白指南(四)- 数据的持久化保存(草稿)
  • 原文地址:https://www.cnblogs.com/infinite7/p/12929864.html
Copyright © 2020-2023  润新知