OO_JML_单元总结
OO_JML_单元总结
概述
本单元作业主要学习的是规格化设计,即契约式编程,主要工作是根据所给出的JML规格描述,实现相应接口来满足功能需求。而本次作业在实现接口的同时要注意对数据结构的把控,并对功能实现算法进行优化,减少云心那个时间,避免出现TLE。
一、梳理JML语言的理论基础、应用工具链情况
理论基础
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.注释结构
JML以javadoc注释的方式来表示规格,每行都以@起头。有两种注释方式,行注释和块注释。其中行注释的表示方式为 //@annotation ,块注释的方式为 /* @ annotation @*/ 。
2.JML表达式
-
原子表达式
-
\result表达式:表示一个非 void 类型的方法执行所获得的结果,即方法执行后的返回值。
-
\old( expr )表达式:用来表示一个表达式 expr 在相应方法执行前的取值。
-
... ...
-
-
量化表达式
-
\forall表达式:全称量词修饰的表达式,表示对于给定范围内的元素,每个元素都满足相应的约束。
-
\exists表达式:存在量词修饰的表达式,表示对于给定范围内的元素,存在某个元素满足相应的约束。
-
... ...
-
-
操作符
-
子类型关系操作符
-
等价关系操作符
-
推理操作符
-
... ...
-
3.方法规格
-
前置条件(pre-condition):前置条件通过requires子句来表示: requires P。
-
后置条件(post-condition):后置条件通过ensures子句来表示: ensures P。
4.类型规格
-
不变式(invariant)是要求在所有可见状态下都必须满足的特性,语法上定义 invariant P ,其中 invariant 为关键词, P 为谓词。对于类型规格而言,可见状态(visible state)是一个特别重要的概念。
-
状态变化约束(constraint)对象的状态在变化时往往也许满足一些约束,这种约束本质上也是一种不变式。
应用工具链
-
openJML:可以根据JML对实现进行语法检查和静态检查。
-
JMLUnitNG:可以根据JML自动生成对应的测试样例,用于进行单元化测试。
二.部署SMTSolver,至少选择3个主要方法来尝试进行验证,报告结果
测试程序如下:
1 public class MyPath1 implements Path { 2 // Iterable<Integer>和Comparable<Path>接口的规格请参阅JDK 3 //@ public instance model non_null int[] nodes; 4 private ArrayList<Integer> 5 nodes = new ArrayList<>(); 6 //@ ensures \result == nodes.length; 7 public /*@pure@*/int size(){ 8 return nodes.size(); 9 } 10 11 /*@ requires index >= 0 && index < size(); 12 @ assignable \nothing; 13 @ ensures \result == nodes[index]; 14 @*/ 15 public /*@pure@*/ int getNode(int index){ 16 return nodes.get(index); 17 } 18 19 //@ ensures \result == (\exists int i; 0 <= i && i < nodes.length; nodes[i] == node); 20 public /*@pure@*/ boolean containsNode(int node){ 21 return nodes.contains(node); 22 } 23 24 25 /*@ ensures (\exists int[] arr; (\forall int i, j; 0 <= i && i < j && j < arr.length; arr[i] != arr[j]); 26 @ (\forall int i; 0 <= i && i < arr.length;this.containsNode(arr[i])) 27 @ && (\forall int node; this.containsNode(node); (\exists int j; 0 <= j && j < arr.length; arr[j] == node)) 28 @ && (\result == arr.length)); 29 @*/ 30 public /*pure*/ int getDistinctNodeCount(){ 31 ArrayList<Integer> tempList = new ArrayList<>(); 32 Iterator<Integer> it = this.iterator(); 33 while (it.hasNext()) { 34 int temp = it.next(); 35 if (!tempList.contains(temp)) { 36 tempList.add(temp); 37 } 38 } 39 return tempList.size(); 40 } 41 42 /*@ also 43 @ public normal_behavior 44 @ requires obj != null && obj instanceof Path; 45 @ assignable \nothing; 46 @ ensures \result == (((Path) obj).nodes.length == nodes.length) && 47 @ (\forall int i; 0 <= i && i < nodes.length; nodes[i] == ((Path) obj).nodes[i]); 48 @ also 49 @ public normal_behavior 50 @ requires obj == null || !(obj instanceof Path); 51 @ assignable \nothing; 52 @ ensures \result == false; 53 @*/ 54 public boolean equals(Object obj){ 55 if (!(obj instanceof Path)) { 56 return false; 57 } 58 if (this.size() != ((Path) obj).size()) { 59 return false; 60 } 61 for (int i = 0; i < this.size(); i++) { 62 if (this.getNode(i) != ((Path) obj).getNode(i)) { 63 return false; 64 } 65 } 66 return true; 67 } 68 69 //@ ensures \result == (nodes.length >= 2); 70 public /*@pure@*/ boolean isValid(){ 71 if (this.size() >= 2) { 72 return true; 73 } else { 74 return false; 75 } 76 } 77 78 public MyPath1(int[] nodeList) { 79 for (int i = 0; i < nodeList.length; i++) { 80 nodes.add(nodeList[i]); 81 } 82 } 83 84 @Override 85 public Iterator<Integer> iterator() { 86 return nodes.iterator(); 87 } 88 89 @Override 90 public int compareTo(Path o) { 91 for (int i = 0; i < o.size() && i < this.size(); i++) { 92 if (o.getNode(i) > this.getNode(i)) { 93 return -1; 94 } else if (o.getNode(i) < this.getNode(i)) { 95 return 1; 96 } 97 } 98 if (o.size() == this.size()) { 99 return 0; 100 } else if (o.size() > this.size()) { 101 return -1; 102 } else { 103 return 1; 104 } 105 /* 106 Iterator<Integer> itThis = this.iterator(); 107 Iterator<Integer> itOo = o.iterator(); 108 int temp1, temp2; 109 while (itThis.hasNext()) { 110 temp1 = itThis.next(); 111 temp2 = itOo.next(); 112 if (temp1 > temp2) { 113 return 1; 114 } else if (temp1 < temp2) { 115 return -1; 116 } 117 } 118 */ 119 } 120 121 @Override 122 public int hashCode() { 123 return this.nodes.hashCode(); 124 } 125 126 //@ ensures containsNode(nodeId) ==> \result == Math.pow(4, (nodeId % 5 + 5) % 5); 127 //@ ensures !containsNode(nodeId) ==> \result == 0; 128 public /*@pure@*/ int getUnpleasantValue(int nodeId){ 129 if(containsNode(nodeId)) { 130 return (int)Math.pow(4, (nodeId % 5 + 5) % 5); 131 } 132 else { 133 return 0; 134 } 135 } 136 }