网站首页
JSP空间
动态资讯
开源项目
技术文档
资源下载
J2EE资源
客户论坛
在线支付
 
  技术文档>>JAVA>>新手入门>>基础入门>查看文档  
  jml起步--使用jml 改进你的java程序(2)     
  文章作者:未知  文章来源:水木森林  
  查看:66次  录入:管理员--2007-11-17  
 
  来自:http://www-106.ibm.com/ 作者:joe verzulli


量词(quantification)(译者注:这里量词的意思与逻辑学上的量词意思相近,而不是普通意义上理解的量词。)


在上面pop()方法的行为规范中,我们说它的返回值要等于peek()方法的返回值,不过我们并没有看到关于peek()方法的规范。priorityqueue中peek()方法的行为规范请看下面的代码:



代码段3 priorityqueue 中peek()方法的行为规范





/*@

@ public normal_behavior

@ requires ! isempty();

@ ensures elementsinqueue.has(esult);

@*/

/*@ pure @*/ object peek() throws nosuchelementexception;



jml标记要求只有当队列中至少含有一个元素的时候,才能调用peek()方法,同时他还要求方法的返回值必须在elementsinqueue之内,也就是说,这个返回值一定是这个队列中的一个元素。



注释/*@ pure @*/ 表明peek()方法是一个纯方法(pure method),纯方法是指没有副作用的方法。jml中只允许使用纯方法进行断言确认,所以我们把peek()声明为纯方法,这样我们就可以在pop()方法的后置条件中使用peek()方法。大家肯定想知道,为什么jml只允许使用纯方法进行断言确认?问题是这样的,如果jml允许使用非纯方法进行断言确认的话,我们稍不注意就会写出有副作用的行为规范。比如说可能会有这么一种情况,开启了断言确认以后,我们的代码正确无误,可是如果禁止了断言确认后,我们的代码却不能运行了,或运行出错了。这样当然不行!后面,我们还会进一步讨论副作用的问题。

关于继承



jml行为规范可以被子类(含子接口)或者是实现接口的类所继承,这一点与j2se1.4中断言有所不同。jml关键字 also表示当前定义的行为规范与祖先类或被实现的接口中所定义的行为规范一起作用。因而,在 priorityqueue接口定义的 peek()方法的行为规范同样适用于 binaryheap类中的 peek()方法。这个就意味着,虽然在 binaryheap.peek()的行为规范中没有明确定义, binaryheap.peek()的返回值也必须在 elementsinqueue当中。




大顶堆和小顶堆(译者注:大顶堆和小顶堆是数据结构里面的概念,分别表示堆排序方法的不同实现方式。堆排序是一种通过调整二叉树进行排序的方法。)


上面我们给peek()定义的行为规范明显缺少了一块,那就是我们根本没有要求它返回的那个元素具有最大的优先级。显然,jccc的priorityqueue接口既可以用于大顶堆,也可以用于小顶堆。大顶堆和小顶堆的表现是有些差别的,在小顶堆中优先级最高的元素值最小,而大顶堆中优先级最高的元素值最大。因为priorityqueue并不知道自己被用来进行大顶堆排序还是小顶堆排序,所以指定返回哪个元素的规范必须在实现priorityqueue接口的类中进行定义。



在jccc 中,类 binaryheap实现了priorityqueue接口。binaryheap允许使用它的客户代码在构造函数中通过一个参数来指定排序方案,也就是通过参数来指定是通过大顶堆方式排序还是通过小顶堆方式排序。我们使用一个boolean模型变量isminimumheap来判断binaryheap的排序方式是大顶堆还是小顶堆。下面的例子是binaryheap使用isminimumheap给peek()方法定义的行为规范:





代码段4 binaryheap 类中peek()方法的行为规范





/*@

@ also

@ public normal_behavior

@ requires ! isempty();

@ ensures

@ (isminimumheap ==>

@ (forall object obj;

@ elementsinqueue.has(obj);

@ compareobjects(esult, obj)

@ <= 0)) &&

@ ((! isminimumheap) ==>

@ (forall object obj;

@ elementsinqueue.has(obj);

@ compareobjects(esult, obj)

@ >= 0));

@*/

public object peek() throws nosuchelementexception



使用量词


上面代码段4中的后置条件包含两个部分,分别用于大顶堆和小顶堆的情况。“==>”符号的意思是包含(译者注:这个包含与逻辑学中包含的意思一致)。x ==> y 当且仅当y为真或x为假时取真值。对于小顶堆排序来说,适用下面所列的代码:



(forall object obj;

elementsinqueue.has(obj);

compareobjects(esult, obj) <= 0)



上面的代码中forall是一个jml量词。上面forall表达式当所有的对象obj满足elementsinqueue.has(obj)为真且compareobjects(esult, obj)返回一个非正数两个条件时才为真。换言之,当使用compareobjects()进行比较时,peek()方法的返回值一定小于或等于elementsinqueue中每一个元素的值。其他的jml量词还有exists、sum以及 min等等。



使用comparator进行比较


binaryheap类允许以两种方法比较元素的大小。一种方法是要进行比较的元素自己实现comparable接口,比较过程使用元素中定义的方法进行。另外一种方法是客户类在构造binaryheap类的实例时向构造函数传入一个comparator对象,使用该comparator对象进行比较。无论使用哪一种比较方式,我们都使用模型域comparator来表示比较大小所用的comparator对象。 在peek()方法的后置条件中,compareobjects()方法使用客户端选择的比较方式来进行元素的比较。compareobjects()方法定义如下:



代码段5 compareobjects() 方法





/*@

@ public normal_behavior

@ ensures

@ (comparator == null) ==>

@ (esult == ((comparable) a).compareto(b)) &&

@ (comparator != null) ==>

@ (esult == comparator.compare(a, b));

@

@ public pure model int compareobjects(object a, object b)

@ {

@ if (m_comparator == null)

@ return ((comparable) a).compareto(b);

@ else

@ return m_comparator.compare(a, b);

@ }

@*/



compareobjects方法的定义中使用了另外一个关键字model,它的意思是compareobjects方法是一个模型方法。模型方法是只能用在行为规范中的jml方法。模型方法定义在java的注释中,所以常规的java代码不能使用。



如果binaryheap类的客户代码指定了一个特殊的comparator用来进行比较的话,m_comparator就指向那个comparator,否则m_comparator的值就是null。compareobjects()方法检查m_comparator的值,然后采用适当的方法进行元素间的比较。



模型域如何取值


在代码段4中我们讨论了peek()方法的后置条件。这个条件保证peek()方法的返回值的优先级大于或者等于模型域elementsinqueue中所有的元素的优先级。那么有一个问题,像elementsinqueue这样的模型域如何取值?前置条件、后置条件和不变量都是没有副作用的,所以不能使用它们来设置模型域的值。



jml使用一个represents语句把模型域与具体的实现域关联起来。比如下面的represents语句用来给模型域isminimumheap赋值:



//@ private represents isminimumheap <- m_isminheap;



这个语句的意思是模型域isminimumheap的值等于m_isminheap的值,其中,m_isminheap是binaryheap类中一个私有的布尔变量。 一旦需要用到isminimumheap的值,jml就会把m_isminheap的值赋给它。



represents语句并没有限制<-右边必须是成员变量。比如说,下面是elementsinqueue的represents语句:



代码段6 elementsinqueue 的represents语句





/*@ private represents elementsinqueue

@ <- jmlobjectbag.convertfrom(

@ arrays.aslist(m_elements)

@ .sublist(1, m_size + 1));

@*/



从这里我们可以看出,elementsinqueue的元素就是数组m_elements[]从第一个元素到第m_size个元素共m_size个元素构成的列表,其中数组m_elements[]是binaryheap的一个私有成员,用来存储优先级队列中的元素,m_size是m_elements[]中正在使用的元素的个数。类binaryheap没有使用m_elements[0],这样可以简化对于索引的操作。jmlobjectbag.convertfrom()的作用是把一个list结构转化为一个elementsinqueue所需要的jmlobjectbag结构。这样一旦jml运行时进行断言检查的时候需要elementsinqueue的值,系统就会计算represents 语句<-符号右边的代码并进行求值。



下面我们来看一下副作用和异常行为。
 
 
上一篇: jive中的设计模式    下一篇: jml起步--使用jml 改进你的java程序(3)
  相关文档
用java实现利用搜索引擎收集网址的程序 11-16
让java说话-用java实现语音引擎 11-16
使用ant编译打包应用程序 11-17
java的秘密:将应用程序的设定存在哪里 11-17
学习如何使 java 应用程序启动更快以及占用更少的内存 11-17
数据库中数据项变化不定,如何设计java beans(1) 11-17
java高级编程:java语言的网络功能与编程 11-16
java基础:初学者java语言入门精典文章 11-16
学习java&xml心得(2) 11-16
一年java之路的回顾,反思以及展望 11-17
最新sun认证考试通过分数题量分布表 11-17
在 websphere as 中使用 web 服务安全性 11-17
java中容易搞错的一些东东 11-17
resin和iis配置多个站点 11-17
think in java 3rd 中文版9 11-17
实现j2ee中的多字节字符处理(组图) 11-17
robocode 高手的秘诀:因数避墙法 11-17
在j2ee web 应用中使用基于captcha 的授权模块 11-17
使用技巧 如何用java读取excel文件内容 11-16
hibernate作为数据持久层的分析和研究 11-17
返回首页 | 关于我们 | J网章程 | JSP空间合租 | 客服中心 | 免责声明 | 常见问题 | 参观机房
本站主机空间代理至厦门市华众网络科技有限公司
《中华人民共和国增值电信业务经营许可证》
编号:闽B2-20050079
@2005-2008福建JSP技术网 版权所有 闽ICP备05000928号
厦门(总部):13616026886 福州:0591-87655121
邮箱:admin@fjjsp.com 站长QQ,点击这里给我发消息