java jml_JML 入门

【IT168 技术文章】面向对象分析和设计的原则之一就是应当尽可能地把过程设想往后推。我们大多数人只在实现方法之前遵守这一规则。一旦确定了类及其接口并该开始实现方法时,我们就转向了过程设想。那么到底有没有别的选择?和大多数语言一样,编写 Java 代码时,我们需要为计算每个方法的结果一步一步地提供过程。

就其本身而言,过程化表示法只是说 如何做某事,却不曾说过我们正在设法做 什么。在动手之前了解我们想要取得的结果,这可能会有用,但是 Java 语言没有提供显式地将这种信息合并到代码中的方法。

Java 建模语言(JML)将注释添加到 Java 代码中,这样我们就可以确定方法所执行的内容,而不必说明它们如何做到这一点。有了 JML,我们就可以描述方法预期的功能,无需考虑实现。通过这种方法,JML 将延迟过程设想的面向对象原则扩展到了方法设计阶段。

JML 为说明性的描述行为引入了许多构造。这些构造包括模型字段、量词、断言的可见度范围、前提条件、后置条件、不变量、合同继承以及正常行为与异常行为的规范。这些构造使得 JML 的功能变得非常强大,但是没必要理解或使用所有这些构造,也没必要马上使用所有的构造。您可以从简单的起点开始逐步学习和使用 JML。

在本文中,我们将采取循序渐进的方法来学习 JML。我们将从概述使用 JML 的好处入手,重点讲述它对开发和编译过程的影响。接下来,我们将讨论用于前提条件、后置条件、模型字段、量化、副作用和异常行为的 JML 构造。在这个过程中,示例会显示每种 JML 构造的动机。在本文结尾处,您将对 JML 的工作原理有个概念性的理解,并能将它应用到您自己的程序中。

JML 概述

使用 JML 来说明性地描述所希望的类和方法的行为,可以显著地改善整个开发过程。将建模表示法添加到 Java 代码中,其好处包括以下几点:

能更加精确地描述代码所完成的任务

能有效地发现和纠正错误

能减少随着应用程序的进展而引入错误的机会

能较早地发现客户没有正确使用类

能产生始终与应用程序代码保持同步的精确文档

JML 注释始终位于 Java 注解(comment)内部,因此它们不会对进行正常编译的代码产生影响。当我们想将类的实际行为与其 JML 规范进行比较时,可以使用开放源码 JML 编译器。用 JML 编译器编译过的代码如果没有做到规范中规定它应该做的事,那么该代码在运行时会抛出 JML 异常。这不仅能捕获代码中的错误,还能确保文档(JML 注释格式)与代码保持同步。

在以下几节中,我将使用开放源码 Jakarta 公共集合组件(Jakarta Commons Collection Component,JCCC)的 PriorityQueue 接口和 BinaryHeap 类来说明 JML 的特性。

需求和职责

本文的源代码包括了 JCCC 的 PriorityQueue 接口。 PriorityQueue 接口包含了方法特征符,这些特征符指定了参数和返回值的数据类型,但是没有说明任何有关方法行为的内容。我们希望能指定 PriorityQueue 的语义,这样的话实现它的所有类就能以预期的方式运作(在没有行为规范的情况下,我们最终会得到一个实现了 PriorityQueue 接口的堆栈类,或者其它某种非常规的情况)。

请研究 PriorityQueue 中 pop() 方法。优先级队列对 pop() 有什么需求呢?有三个基本需求。首先,除非队列中至少有一个元素,否则不应该调用 pop() 。其次,它应当返回队列中优先级最高的元素。最后,它应当除去从队列中返回的元素。

清单 1 演示了表示第一个需求的 JML 注释:

清单 1. pop() 方法需求的 JML 注释

1 /*@2 3 @ public normal_behavior4 5 @ requires ! isEmpty();6 7 @*/8 9 Object pop()throwsNoSuchElementException;10

如前面所述,JML 注释是写在 Java 注解内部的。包含 JML 的多行注解是以字符 /*@ 开头的。JML 忽略行中所有作为第一个非空格字符的 @ 符号。JML 还可以写在以 //@ 开头的单行注解内部。

这里 JML 中 public 关键字的意义和在 Java 语言中的意义是一样的。 public 表示该 JML 规范对于应用程序中的其它所有类都是可见的。公共规范只能涉及公共方法和成员变量。JML 还允许规范拥有 private 、 protected 或 package 级别的作用域。JML 的作用域规则与 Java 语言中的相应规则类似。

normal_behavior 关键字表示该规范描述了 pop() 正常返回而没有抛出异常的情况。随后我们将讨论如何确定异常行为。

前提条件和后置条件

JML 关键字 requires 用于前提条件。 前提条件(precondition)指的是在调用方法之前必须要满足的条件。清单 1 指出 pop() 的前提条件是 isEmpty() 返回 false ;也就是说,队列中至少要包含一项。

方法的 后置条件(postcondition)指定该方法的职责;也就是说,当方法返回时,后置条件应当是 true。在我们的示例中, pop() 应当返回队列中拥有最高优先级的元素。我们希望指定该后置条件,这样 JML 就可以在运行时检查它。要做到这一点,我们需要清楚已经添加到优先级队列中的所有值,以便确定 pop() 应当返回哪一个值。我们可以考虑将一个成员变量添加到 PriorityQueue 以便在队列中存储这些值,但是这里有两个问题:

PriorityQueue 是一个接口,因此它应当与不同的实现(比如二进制堆、Fibonacci 堆或日历队列)兼容。 PriorityQueue 的 JML 注释不应当描述任何有关实现的内容。

作为接口, PriorityQueue 只能包含静态成员变量。

JML 用 模型字段的概念解决了这一两难局面。

模型字段

模型字段类似于只能在行为规范中使用的成员变量。下面有一个在 PriorityQueue 中使用的模型字段声明示例:

//@ public model instance JMLObjectBag elementsInQueue;

该声明指出有一个模型字段 elementsInQueue ,其数据类型为 JMLObjectBag (属于 JML 的 bag 数据类型)。 instance 关键字表示:即使该字段是在接口中进行声明的,也要在实现 PriorityQueue 的类的每个实例中分别放置该字段的非静态副本。和所有 JML 注释一样, elementsInQueue 的声明出现在 Java 注解中,因此 elementsInQueue 不能用于正规的 Java 代码中。没有哪个对象会在运行时包含 elementsInQueue 字段。

elementsInQueue 包含了添加到优先级队列的值。清单 2 显示了 pop() 的规范是如何利用 elementsInQueue 的:

清单 2. pop() 的后置条件中所使用的模型字段

1 /*@2 3 @ public normal_behavior4 5 @ requires ! isEmpty();6 7 @ ensures8 9 @ elementsInQueue.equals(((JMLObjectBag)10 11 @ \old(elementsInQueue))12 13 @ .remove(\result)) &&14 15 @ \result.equals(\old(peek()));16 17 @*/18 19 Object pop()throwsNoSuchElementException;20 21

ensures 关键字指出其后跟的是 pop() 返回时必须满足的后置条件。 \result 是 JML 关键字,它等于 pop() 所返回的值。 \old() 是 JML 函数,在调用 pop() 之前它返回其参数所具有的值。

ensures 子句包含两个后置条件。第一个指出将 pop() 所返回的值从 elementsInQueue 中除去。第二个指出返回值和 peek() 返回的值一样。

类级不变量

我们已经看到 JML 允许我们指定方法的前提条件和后置条件。它还允许我们指定类级不变量。类级不变量是这样的条件:即在类中每个方法的入口和出口处这些条件都必须为 true。例如, //@ public instance invariant elementsInQueue != null; 是 PriorityQueue 的不变量,这就是说,在实现 PriorityQueue 的类的构造函数返回之后, elementsInQueue 无论何时都不能是 null。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/459819.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

转移指令检测题9

补全编程,利用loop指令,实现在内存2000H段中查找第一个值为0的字节,找到后,将它的偏移地址存储在DX中 assume cs:code code segment start:mov ax,2000h mov ds,ax mov bx,0 s: mov cl,[bx] mov ch,0 inc cx ;此处为要…

c语言 java append_C++中append函数的用法和函数定义。谢谢!

展开全部要想使用标准C中string类,必须要包含#include // 注意是,不62616964757a686964616fe78988e69d8331333339663434是,带.h的是C语言中的头文件using std::string;using std::wstring;或using namespace std;下面你就可以使用string/wstr…

PHP array_flip() array_merge() array+array的使用总结

array_flip(array); //传递一个数组参数,对该数组的键、值进行翻转 例如: $a array(a,b,c ); print_r(array_flip($a));//输出为: Array ([a] > 0[b] > 1[c] > 2 )//需要注意的是: array_flip(): Can only flip STRING …

很好用的程序员在线画图软件

今天向大家推荐一个很好用的在线画图软件:今天向大家推荐一个很好用的在线画图软件:今天向大家推荐一个很好用的在线画图软件:(重要的事情说三篇)连接地址如下:https://www.processon.com/i/55e3195de4b0df…

java breakpoint_java断点

第一步:用firefox运行程序,当点击保存,提示保存失败后,启动firebug通过请求找到addNew.ezt出现错误,在eztnews.xml里通过ctrlF查找找到请求执行的类和方法找到NewsAction类的doAddNew方法然后在通过找到NewsActions.ja…

1)C++对象大小计算

C对象的大小不同的编译器的实现是不一样的,以下仅讨论.net2003,其他编译的可能出现的结果以下也做了分析和猜测。在反推不同编译器实现的C对象的大小时。对齐是一个很重要也容易被遗忘的问题。class A{}; 类A是一个空类,但是它的大小并不…

OC之ARC环境中的循环strong问题

2019独角兽企业重金招聘Python工程师标准>>> main.m文件&#xff1a; #import <Foundation/Foundation.h> #import "Person.h" #import "Dog.h"int main() {Person *p [[Person alloc] init];Dog *d [[Dog alloc] init];p.dog d;d.per…

java metric_java版的Metric工具介绍

Metrics是一个给JAVA服务的各项指标提供度量工具的包&#xff0c;在JAVA代码中嵌入Metrics代码&#xff0c;可以方便的对业务代码的各个指标进行监控&#xff0c;同时&#xff0c;Metrics能够很好的跟Ganlia、Graphite结合&#xff0c;方便的提供图形化接口。基本使用方式直接将…

15_采用Pull解析器解析和生成XML内容

java还提供SAX和DOM用于解析XML Android还集成了Pull解析器——推荐 package cn.itcast.service;import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1…

Android自定义view之圆形进度条

本节介绍自定义view-圆形进度条思路&#xff1a;根据前面介绍的自定义view内容可拓展得之&#xff1b;1&#xff1a;新建类继承自View2&#xff1a;添加自定义view属性3&#xff1a;重写onDraw(Canvas canvas)4&#xff1a;实现功能下面上代码1.自定义view代码&#xff1a; pub…

java二级考试备考_2017计算机二级考试《JAVA》备考测试题「带答案」

2017计算机二级考试《JAVA》备考测试题「带答案」为确保同学们将所涉及的考点全面复习到位&#xff0c;让大家充满信心的步入考场&#xff0c;以下是百分网小编搜索整理的一份计算机二级考试《JAVA》备考测试题【带答案】&#xff0c;供参考练习&#xff0c;希望对大家有所帮助…

Thinkphp 关联模型和试图模型区别

关联模型主要在多表操作时使用&#xff0c;比如 user表&#xff0c;user_role表&#xff0c;role表 user_role字段&#xff1a;uid,rid&#xff0c;它作为中间表&#xff0c;负责将user和role之间的&#xff0c;1对1&#xff0c;1对多&#xff0c;多对多的关系进行保存。 这时要…

windows7下安装php的imagick和imagemagick扩展教程

这篇文章主要介绍了windows7下安装php的imagick和imagemagick扩展教程,同样也适应XP操作系统,Win8下就没测试过了,需要的朋友可以参考下 最近的PHP项目中&#xff0c;需要用到切图和缩图的效果&#xff0c;在linux测试服务器上很轻松的就安装好php imagick扩展。但是在本地wind…

java 线程间通信 handler_Handler不同线程间的通信

转http://www.iteye.com/problems/69457Activity启动后点击一个界面按钮后会开启一个服务(暂定为padService)&#xff0c;在padService中会启动一个线程(暂定为Thread-3)发起Socket连接。我们项目中使用mina作为socket通信框架&#xff0c;用过mina的同志们应该熟悉&#xff0c…

通过mysql show processlist 命令检查mysql锁的方法

作者&#xff1a; 字体&#xff1a;[增加 减小] 类型&#xff1a;转载 时间&#xff1a;2010-03-07show processlist 命令非常实用&#xff0c;有时候mysql经常跑到50%以上或更多&#xff0c;就需要用这个命令看哪个sql语句占用资源比较多&#xff0c;就知道哪个网站的程序问题…

java流类图结构_java学习之IO流(学习之旅,一)

个人在学习IO流的时候看到如下所示java 流类图结构的时候&#xff0c;我的感想是&#xff0c;这么多处于蒙的状态。Java流类图结构这么多&#xff0c;没有分类不好学&#xff0c;那我们就慢慢一口一口的吃&#xff0c;这样每天学习一点就好了&#xff0c;其实很多类并不是常用的…

php 安装xdebug扩展

php 扩展获取地址 http://pecl.php.net/package/ 编译安装的过程 wget http://pecl.php.net/get/xdebug-2.2.2.tgz tar -zxvf xdebug-2.2.2.tgz cd xdebug-2.2.2/ /data/klj/php/bin/phpize ./configure --enable-xdebug --with-php-config/data/klj/php/bin/php-config mak…

通过VB向SQL Server数据库中录入数据

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)一、数据录入通过VB向SQL Server数据库中录入数据&#xff0c;可以使用数据绑定控件录入数据与使用SQL语句录入1.利用数据绑定控件录入数据使用数据绑定控件录入数据可以运行较少的代码&…

拨打电话 java_简单拨打电话程序

众所周知,对于一个手机,能拨打电话是其最重要也是最常用的一个功能.而在Android里是怎么样实现拨打电话的程序呢?我在这里写了一个简单的拨打电话的Demo,供大家参考.一共分为5个步骤.Step 1:新建一个Android工程,命名为phoneCallDemo.Step 2:设计程序的界面,打开main.xml把内容…

Apple开发者账号申请学习方式

http://jingyan.baidu.com/article/414eccf610e7c76b431f0a94.html https://developer.apple.com/wwdc/schedule/转载于:https://www.cnblogs.com/wcLT/p/4167707.html