OO第三单元——JML规格化设计
OO第三单元——JML规格化设计
JML语言的理论基础以及应用工具链情况
理论基础
JML是对JAVA程序进行规格化设计的一种表示语言,是一种行为接口规格语言。JML整合了Java和JAVAdoc,并且引入了并要的形式化表达手段。
其方法规格核心包括:前置条件、后置条件和副作用约定。通过对方法的出入参数、执行结果以及可以修改的对象的属性/类的静态成员变量的限制,来保证方法的执行。书写规格时无需关系具体怎么做,只需关心调用方法后的结果。类型规格包括不变式约束和约束限制。
JML语言的两个主要用法是:开展规格化设计,保证逻辑的严谨严格;针对已有代码,书写规格,从而提高代码的可维护性
工具链
- openjml检测JML的书写是否合格
- SMT Solver验证程序的等价性
- JMLUnitNG/JMLUnit可以根据规格自动生成测试用例,进行测试。
JMLUnitNG的初步使用
我使用一个简单的程序进行了初步的尝试。
public class Main {
//@ ensures \result == (a+b);
public static int add(int a, int b) {
return a + b;
}
//@ ensures \result == (a*b);
public static int mul(int a, int b) {
return a * b;
}
public static void main(String[] args) {
int num1 = 3;
int num2 = 5;
add(num1, num2);
mul(num1, num2);
}
}
生成测试文件
java -jar jmlunitng.jar src/Main.java
编译测试文件
javac -cp jmlunitng.jar src/**.java
在IDEA中运行
Main_JML_Test.java(要将jmlunitng.jar设为待测试的外部依赖包)
运行结果:

从自动生成的测试样例来看,自动生成的测试样例重点测试了一些边界条件。主要针对MAX_VALUE,MIN_VALUE和0
架构设计分析
这一单元的作业中,我们依次实现了支持增删查的Path的容器,无向图系统,以及最后的地铁站系统,而且我们每次只需要完成两个核心类,代码体验要比前两次要好。这三次作业之间PathContainer抽象接口的继承让人感觉非常舒服,很OO。
- 第一次作业

本次作业不难。在MyPathContainer中,由于作业要求中查找操作占比大,为了提高查找效率,用两个
HashMap来存放Path。其键值对分别为<MyPath,ID>和<ID,MyPath。另外,为了满足题目中求不同节点个数的要求,我另外使用一个HashMap来存放不同的节点,其键值对<节点,该节点出现的频次>。在每次有MyPath的增删时,更新这三个数据结构。第二次作业

由于这次要实现一个无向图系统,因此我新增了一个edge类,表示两点之间的一条连边。其成员变量为两个int 型的数据,表示这条边所连接的两个点。并重写了
hashCode()和equals()方法。这次作业的难点:一是判断两点是否联通,另一个是求两点间的最短距离。我是将这两个一起解决的。
- 使用
HashMap来实现一个类似距离矩阵的数据结构。Edge作为key,被Edge连接的两点间的距离作为Value。每次增删PATH时对这个数据结构进行维护 - 利用
distinctNode和distinctEdge进行初始化,相同点之间连边Value为0,其他的:若连边存在于distinctEdge,则将Value置为1,否则置为无穷(一个很大的数)。之后利用floyd算法进行最短距离的计算。 - 查找最短距离时只需在
distances中寻找即可。 - 在判断是否连通时,在
distances中查找,若距离大于等于之前设的那个很大的数,则说明不连通。否则连通。
- 使用
第三次作业

这次的难点在于换乘权重的加入。换乘权重在求最低不满意度、最少票价和最少换乘时都是块硬骨头。一开始我是没有什么思路的,感谢讨论区大佬的分享让我顺利完成作业。整合之后,这三个要求其实是一样的,都是求两点间最短加权距离的问题。难点在于如何处理换乘权重上。我最后的实现:
- 对于每条Path,构建完全图,针对不同要求计算不同的加权距离矩阵,计算完后将换乘权重先加到距离矩阵上。
- 利用所有存在的Path的加权距离矩阵构建地铁系统中对应的加权距离矩阵。之后利用Floyd算法计算。
- 最后的计算结果减去2,因为最后不用再换乘了。
- 使用的数据结构和之前求最短路一致,全部HashMap莽。
对于求连通块,我用的是并查集算法,用HashMap实现。
指导书的建议与图有关的操作单独封装,这一块的架构设计我做的不好,本来想封装来着,结果封装的类里只有一个floyd算法。
重构分析
我这一单元的作业中,感觉并没有进行很大的架构重构,后面的作业如果和前面有重合,基本上就沿用的上一次的代码,其余就是在原有基础上添加成员变量和方法了。相比于之前的次次重构,感觉要好很多。
作业中出现的bug以及修复情况
"=="和“euqals”的使用——对JAVA的自动拆箱装箱机制理解不到位
public class MyPath implements Path {
private ArrayList<Integer> nodes = new ArrayList<>();
public int getDistinctNodeCount() {
int temp = 1;
ArrayList<Integer> t = new ArrayList<>(nodes);
Collections.sort(t);
for (int i = 1; i < t.size(); i++) {
//if (t.get(i)!=t.get(i - 1)){//这样比较的不是数据本身,而是两个对象的引用。
if (!t.get(i).equals(t.get(i - 1))) {//更改后
temp++;
}
}
return temp;
}
}
问题出在第8行,我以为JAVA的自动拆装箱机制可以保证我比较的是两个int 类型的数据,但出现错误之后查阅资料发现:当 "==","!="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。因此要改成equals。
令人头脑发麻的TLE——一个高质量的hashCode()的重要性
遇到TLE是在第二次作业的强测和互测,两者加起来一共有11刀,一般看到TLE我能想的就只有重构了,正在我发愁的时候,经人提醒我意识到可以先优化
hashCode()方法,减少哈希冲突对时间性能的提高也是大有帮助的。public class Edge {
private int fromid;
private int toid;
public int hashCode() {
return (fromid + toid);
}//更改前,两个数字简单相加
public int hashCode() {
if (fromid < toid) {
return fromid * 31 + toid;
} else {
return toid * 31 + fromid;
}
}//更改后,两个int的数据,如何构造hashCode
}
参考网上一些优化方法修改了HashCode之后,11刀全都被修复了,妈妈再也不用担心我的TLE了。
关于规格撰写和理解的心得体会
个人感觉这一单元的侧重点明显和前两单元有所不同,规格化设计让人更能从设计角度理解OOP思想。首先,规格的存在使得要求不再存在二义性(然而规格写错就比较尴尬)。感觉规格和离散数学相通,更像是用数学的方法来约束代码。再者个人认为规格太过于繁琐,有时候明明几行代码就能解决的问题,非要先写很长的规格来进行约束,这个给规格的撰写和理解都带来很大难度。对我个人而言,感觉规格的撰写还是有难度的。一旦方法有些复杂,就会对规格从何写起没有头绪,不知如何上手。撰写规格比写代码更要求逻辑清晰,数学表达能力强。
OO第三单元——JML规格化设计的更多相关文章
- OO第三单元——JML之破分大法
一.Jml总结及应用工具链 总的来说,jml就是对java程序进行规格化设计的一种表示语言,其中最核心的就是规格化,将代码要实现的功能和各项要求与约束不是通过自然语言,而是通过严密的逻辑语言来表达,这 ...
- 北航面向对象OO第三单元——JML
简介 本单元借助JML(Java Modeling Language),训练了我们关于的"规格(specification)"的意识和思想 本单元代码难度较低,简单来讲就是给你规定 ...
- OO第三单元JML总结
目录 目录一.JML语言的理论基础二.应用工具链三.部署SMT Solver四.部署JMLUnitNG/JMLUnit五.三次作业分析第一次作业第二次作业第三次作业六.总结与心得体会 一.JML语言的 ...
- OO第三单元
OO第三单元 JML语言理论基础,应用工具链 JML语言基础 JML简介 定义: JML 是一种形式化的. 面向 JAVA 的行为接口规格语言 作用: 开展规格化设计.这样交给代码实现人员的将不是可能 ...
- 规格化设计——OO第三单元总结
规格化设计--OO第三单元总结 一.JML语言理论基础.应用工具链 1.1 JML语言 JML(java modeling language)是一种描述代码行为的语言,包括前置条件.副作用等等.J ...
- OO第三单元(地铁,JML)单元总结
OO第三单元(地铁,JML)单元总结 这是我们OO课程的第二个单元,这个单元的主要目的是让我们熟悉并了解JML来是我们具有规格化编程架构的思想.这个单元的主题一开始并不明了,从第一次作业的路径到第二次 ...
- OO第三单元——基于JML的社交网络总结
OO第三单元--基于JML的社交网络总结 一.JML知识梳理 1)JML的语言基础以及基本语法 JML是用于java程序进行规格化设计的一种表示语言,是一种行为接口规格语言.其为严格的程序设计提供了一 ...
- 2020 OO 第三单元总结 JML语言
title: 2020 OO 第三单元总结 date: 2020-05-21 10:10:06 tags: OO categories: 学习 第三单元终于结束了,这是我目前为止最惨的一单元,第十次作 ...
- OO第三单元作业(JML)总结
OO第三单元作业(JML)总结 目录 OO第三单元作业(JML)总结 JML语言知识梳理 使用jml的目的 jml注释结构 jml表达式 方法规格 类型规格 SMT Solver 部署JMLUnitN ...
随机推荐
- RabbitMQ-如何保证消息在99.99%的情况下不丢失
1. 简介 MQ虽然帮我们解决了很多问题,但是也带来了很多问题,其中最麻烦的就是,如何保证消息的可靠性传输. 我们在聊如何保证消息的可靠性传输之前,先考虑下哪些情况下会出现消息丢失的情况. 首先,上图 ...
- springcloud3(五) spring cloud gateway动态路由的四类实现方式
写这篇博客主要是为了汇总下动态路由的多种实现方式,没有好坏之分,任何的方案都是依赖业务场景需求的,现在网上实现方式主要有: 基于Nacos, 基于数据库(PosgreSQL/Redis), 基于Mem ...
- Ubantu启动失败,提示“Started GNOME Display Manager”之后起不来了
我是在搭建DPDK环境时,为了尝试下多网卡多列配置,将虚拟机的网卡类型由e1000改成了vxnet3类型.之后修改了下内存大小和CPU核数.然后启动ubantu虚拟机,结果无法成功启动,显示结果如下: ...
- PPP协议、PPPoE协议、L2TP协议的关系
1. 简述 首先对这3中协议做一个简单的描述: 协议 协议类型 描述 PPP 点对点链路层协议 应用最广泛的点对点协议,可应用在多种网络,改善了SLIP协议的不足 PPPoE 点对点链路层协议 对PP ...
- JS003. 事件监听和监听滚动条的三种参数( addEventListener( ) )
全局 1 window.addEventListener('scroll', () => { 2 console.log('------') 3 console.log(document.doc ...
- 【第十篇】- Git 远程仓库(Github)之Spring Cloud直播商城 b2b2c电子商务技术总结
Git 远程仓库(Github) Git 并不像 SVN 那样有个中心服务器. 目前我们使用到的 Git 命令都是在本地执行,如果你想通过 Git 分享你的代码或者与其他开发人员合作. 你就需要将数据 ...
- ElasticSearch集成SpringData史上最全查询教程
1.简单介绍 springboot 使用springdata操作es,ElasticsearchRepository使用QueryBuilder构造查询条件 2.集成es //maven集成 < ...
- 【Nginx】Linux常用命令------启动、停止、重启
启动 启动代码格式:nginx安装目录地址 -c nginx配置文件地址 例如: [root@LinuxServer sbin]# /usr/local/nginx/sbin/nginx -c /us ...
- [推荐]MyBatis 核心技术与面试 34 讲
MyBatis 核心技术与面试 34 讲 职业生涯中常被问到: 如何成为某方面的高手? 如何快速搞定某项技术? 我现在的水平处于什么阶段? -- 我暗暗想,我们从小学到中学到大学,经历了大考三六九.小 ...
- java的split方法中的regex参数
我们需要以|进行分割,为了匹配|本身,正则中采用\|进行转义,而Java中\也表示转义,从java到正则需要必须使用\\|进行转义,即split中的\\表示正则的转义.