BUAA_OO_2020_Unit3_总结博客
BUAA_OO_2020_Unit3_总结
2020年春季学期第十三周,OO第三单元落下帷幕,对这个单元的内容JML有了更深的理解,但也有了一些疑惑,下做总结:
一、JML语言以及工具链
经过课上JML语言的学习,以及实验与课下作业自己实践的理解,我认为JML语言通过一个契约对一个待实现的功能进行了一个约束,这个约束包括了我可以使用什么,使用要求是什么,得到结果应该满足什么等等。但对于怎么使用并没有做出限定。所以对于实现过程具有较大的自由度。但是由于功能的复杂性,不同的规格可能具有不同的复杂度,对应的实现过程也有不同的时间、空间复杂度。对于JML的直接翻译是一个十分不好的习惯,这也是我几次作业都出现的一些问题。由于牺牲了深层次的理解,代码必然会出现性能上或者功能上的准确性与鲁棒性。下面是针对JML level 0语法的一些总结:
一些常用表达式 | 对应语义 |
requires | 前置条件限定 |
assignable | 副作用范围限定 |
ensures | 后置条件限定 |
\result | 表示本方法所返回的结果 |
\old | 表示在本方法对此引用内容修改之前的内容 |
\not_assigend(x,y,...) | 表示括号内变量不可在方法中被赋值 |
\not_modified(x,y,...) | 表示括号内变量取值未变化 |
\forall | 表示全称量词,对应三个语句ABC,对于所有的A,若B满足,则C满足 |
\exists | 表示存在量词,对应三个语句ABC,存在一个A,当B满足时,C满足 |
\sum, \product | 表示求取结果,对应三个语句ABC,对于A,当B满足时,对于C的语句执行连加(连乘)得到的结果 |
\max, \min | 表示求取结果,对于三个语句ABC,对于A,当B满足时,返回C的语句中的最大值(最小值) |
<==> | 表示等价关系 |
==>, <== | 表示可以从左推导得右(或从右推导到左) |
\nothing, \everything | 表示一个空集(全集) |
对于方法规格而言,JML有相应的语法逻辑,其往往表述为
/*@ public normal_behavior
@ requires ...
@ assignable \nothing;
@ ensures ...
@ also
@ public exceptional_behavior
@ requires ...
@ signals ...
@*/
public /*@ pure @*/ int ...();
而对于类型规格,JML定义了不变式invariant,状态变化约束constraint来进行限定。
- 不变式要求在所有可见状态下都必须满足的特性
- 状态变化约束来对前序可见状态和当前可见状态的关系进行约束
工具链
本单元的工具链包括官方的OpenJML用以检测JML语法,其可与Eclipse结合进行使用,还包含自动生成测试用例的JMLUnitNG和JMLUnit等,但其测试模式较为简单,所以并不十分具有可使用价值。下面针对我配置的工具链进行介绍。
二、OpenJML
OpenJML由于其为官方开发的检测工具,其可靠性还较高一些,但其可能存在的兼容性问题,导致其不容易跑成功,比如本人尝试了官网的两种配置方法:采用jar包进行命令行配置,以及Eclipse的OpenJML配置均以不是很成功告终。
其中采用命令行配置的大致命令如下:
java -jar openjml.jar -option<check, esc, rac> -exec z3....exe sourcepath.java
其中-check代表进行JML静态检查,-esc代表利用Solver进行静态检查,-rac代表进行运行时检查,-exec对应运行相应的z3软件,后跟需要检查的java文件
但在经过多次尝试之后,命令行仍然会返回许多错误,其中不乏对于\result等基础表达式的无法解析,至今不太清楚具体原因。
Eclipse中OpenJML的配置,本人也进行了简单的配置,获得的反馈似乎没有很多有效信息
总之可能是我的打开方式不对,也有很多同学与我有同样的问题。这个工具可能很强大但是在使用过程之中体验却不是很佳,这个工具可能仍需要改进与优化,或者由一代又一代的OO学子们涌现出的勇者来填补这个坑。
三、使用JUnitNG来对Group进行简单测试
JUnitNG的配置方法较为简单,但是配置的过程也有一番波折,需要对待测class进行一番修改,再执行相应的代码之后得到结果:
java -jar jmlunitng-1_4.jar MyGroup.java
javac -cp jmlunitng-1_4.jar *.java
java -cp jmlunitng-1_4.jar MyGroup_JML_Test
[TestNG] Running:
Command line suite Failed: racEnabled()
Passed: constructor MyGroup(0)
Passed: constructor MyGroup(-2147483648)
Passed: constructor MyGroup(2147483647)
Passed: <<MyGroup@4fc3fcd5>>.addPerson(null)
Passed: <<MyGroup@1aa7381b>>.addPerson(null)
Passed: <<MyGroup@44e65172>>.addPerson(null)
Passed: <<MyGroup@60eeebd5>>.addPerson(java.lang.Object@4ca6665f)
Passed: <<MyGroup@26e579dc>>.addPerson(java.lang.Object@66caa894)
Passed: <<MyGroup@76215e8d>>.addPerson(java.lang.Object@49011bd5)
Passed: <<MyGroup@58401b4c>>.addrelation()
Passed: <<MyGroup@86575d6a>>.addrelation()
Passed: <<MyGroup@1761cf4e>>.addrelation() ===============================================
Command line suite
Total tests run: 12, Failures: 0, Skips: 0
===============================================
通过对反馈结果我们可以看出来,JMLUnitNG可以测试的范围很有限,对数据可能更多测试的边界以及异常情况,对于测试功能可能较为有限(还是自己好好测把)
四、作业架构分析
三次作业以JML为核心,逐步构造了一个较强的功能越来越齐全的社交网络,在作业的逐步迭代的过程中,我的代码,以及对JML的理解也在逐步的完善之中。首先我的代码仍存在的问题就是,继承关系太死,不够将抽象出来的数据结构,进行类的抽象,从而只有干巴巴的group,network,person的实现类。不是说这种实现方式不好,而是从这三个类的名字来看,我们并不能看出来我们具体实现的是如何,而且层次关系也较为平淡。
- 第一次作业
第一次作业由于较为简单(也是我最惨的一次),并不需要采取什么特殊的数据结构与算法,所以我对于Person,Network里的具体数据结构都采用的ArrayList实现,也可能由于第一个单元就产生了这种直接翻译JML的陋习,后两个单元的一些地方都继承了这个习惯。导致后期进行时间估计时出现明显问题,再进一步进行改正。JML语言只是为描述其所限制的条件,而引用一些中间变量/已有pure方法,但我们需解读这些限制背后究竟求取的是什么内容。
第一次作业跟着JML规格进行翻译就可以,但由于其中的查询操作复杂度为On,甚至存在On^2的操作,所以其为第二次作业留下了一些隐患。对于第一次作业的重头戏isCircle,我用了BFS,可能这也是一个成功案例,只要对这个方法进行正常分析,理智分析,就可以获得相应更好的解决方案。
- 第二次作业
第二次作业加入了大型社交网络内小型组的表示,以及数据量的压力。其实已经是对实现的时间复杂度进行了相关要求。对不同容器的方法源码进行阅读,上网查找资料可以帮助我们更好的使用他们。HashMap会根据容量与影响因子进行扩容,ArrayList,Hashset的查找,增加方法的复杂度是怎样的。对于群组Group中的一些属性的获得操作,如果每次获取都进行计算,那在压力测试面前必定会垮掉。(更科学的方法应该是根据数据量,模拟时间进行计算来判断是否会炸掉),所以需要采用存储,更新的方式进行调用。将复杂度降低,并均摊给了其余方法之中,从而降低本算法的时间复杂度。
值得注意的是,本次作业出现了一个没有JML规格的方法,但是没有规格的限制,我们仍需要注意根据方法内容,结合具体实现中需要的细节进行逻辑书写,切不可放松警惕。
- 第三次作业
第三次作业又问我们增加了新的方法,这些方法之中的核心为MinPath,StrongLinked,BlockSum这三个。从这三个方法也能看出来本单元旨在构建一个社交关系的网络,通过网络的一些特点获取其中的信息,运用抽象出的图这个数据结构进行相应的查询操作(这三个方法都为查询操作),从相关的数据量限制也能看出来,为实现最短路,点双连通,以及连通块的查询,我们需要用相应的算法进行实现。
MinPath使用堆优化的Dijstra进行实现,可以将复杂度从O(n^2)降低到O(nlogn),而堆的优化在于每次取出权最小的边,利用java实现的PriorityQueue即可(省时又省力)。BlockSum连通块个数若采用翻译JML进行的话,复杂度应该是O(n^4)(我一开始直接翻译时并没注意到),改用并查集进行操作时,最慢复杂度为O(n),更快的可以保存变量,每次查询时返回即可,在addPerson时+1,在addrelation时当判断两个节点的根节点不是同一个从而合并时-1。并查集的使用可以进一步优化iscircle的实现方式,从而降低iscircle的复杂度。StrongLinked本人未采用Tarjan算法,而是采用了暴力求取的方法(事先经过估计,应该不会爆掉)。注意两个只有互相连通的点不算StrongLinked,从而需要加入特判。
下为三次作业的UML类图,可以看出功能逐步拓展。内容也逐渐优化。
五、bug分析
三次作业分别出现了不同的bug,也产生了不同程度的打击。
第一次作业由于并没有充分读懂JML规格,导致addrelation方法中对于两个id相同获得了错误的响应,从而炸掉了所有的点,也是最惨痛的教训。炸掉之后再次读JML规格,结合学长讲的“对于JML没有规定的行为,在此方法之中也不可以做任何的事”才对此问题有了更深的认识。
第二次作业是对Group方法之中O(n)的查询方法未保存值,从而构造数据卡掉了。应该归因于自己对数据量以及运行时间的把握以及极端情况下测试估计不足导致
第三次作业问题出在qmp之上,由于其没有限制数据量,所以对于我的堆优化Dij没有完全优化,从而导致CPU时间略微超过系统要求时间,从而爆掉了。这次修复bug的过程也是最难的一次过程,也体会到了只有修复到极致,找到可能浪费cpu的所有根源所在才能解决问题(才应该算解决问题)
三次作业发现bug的方案:JUnit简单覆盖测试+与朋友对拍发现问题,效果很显著,但仍欠缺诸如时间的精确把控以及遇到两人都出现的问题缺乏感知的缺陷。
六、感想与总结
第三单元炸了一次强测是最惨的(orz),不过成绩不是主要。通过作业以及实验的设计,我们可以更深层次的了解JML,以及JML背后蕴含的这种规约化的思想,才是弥足珍贵的。但是从整体难度而言,我觉得这个单元可以作为第一单元出现在OO课程之中,让JML思想先嵌入思维,使用继承,多态等行为进行实现。第三次作业也补习了算法上的一小块漏洞,提醒了下学期算法导论课的重要性。面对本学期最后一个单元的学习,也切不可放松警惕,继续前行。
BUAA_OO_2020_Unit3_总结博客的更多相关文章
- Android请求网络共通类——Hi_博客 Android App 开发笔记
今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...
- 一步步开发自己的博客 .NET版(11、Web.config文件的读取和修改)
Web.config的读取 对于Web.config的读取大家都很属性了.平时我们用得比较多的就是appSettings节点下配置.如: 我们对应的代码是: = ConfigurationManage ...
- 一步步开发自己的博客 .NET版(10、前端对话框和消息框的实现)
关于前端对话框.消息框的优秀插件多不胜数.造轮子是为了更好的使用轮子,并不是说自己造的轮子肯定好.所以,这个博客系统基本上都是自己实现的,包括日志记录.响应式布局.评论功能等等一些本可以使用插件的.好 ...
- 【原】Github+Hexo+NextT搭建个人博客
摘要 GitHub 是一个开源项目的托管网站,相信很多人都听过.在上面有很多高质量的项目代码,我们也可以把自己的项目代码托管到GitHub,与朋友们共享交流.GitHub Pages 是Github为 ...
- 我为什么要写LeetCode的博客?
# 增强学习成果 有一个研究成果,在学习中传授他人知识和讨论是最高效的做法,而看书则是最低效的做法(具体研究成果没找到地址).我写LeetCode博客主要目的是增强学习成果.当然,我也想出名,然而不知 ...
- 博客使用BOS上传图片
1.博客平台的选定 从大学开始做个人主页算起,最开始是使用html,CSSS写简单的页面,后面大学毕业之后接触到了WordPress,就开始用WordPress搭建网站.现在还维护着一个农村网站.ht ...
- 在jekyll模板博客中添加网易云模块
最近使用GitHub Pages + Jekyll 搭建了个人博客,作为一名重度音乐患者,博客里面可以不配图,但是不能不配音乐啊. 遂在博客里面引入了网易云模块,这里要感谢网易云的分享机制,对开发者非 ...
- iOS controller解耦探究实现——第一次写博客
大学时曾经做过android的开发,目前的工作是iOS的开发.之前自己记录东西都是通过自己比较喜欢的笔记类的应用记录下了.直到前段时一个哥们拉着我注册了一个博客.现在终于想明白了,博客这个东西受众会稍 ...
- 中文 iOS/Mac 开发博客列表
中文 iOS/Mac 开发博客列表 博客地址 RSS地址 OneV's Den http://onevcat.com/atom.xml 一只魔法师的工坊 http://blog.ibireme.com ...
随机推荐
- 11_ArrayList集合的方法
class Program { static void Main(string[] args) { //数组:长度不可变,类型单一 //ArrayList集合:长度可以任意改变,类型可以不单一 //创 ...
- 网鼎杯玄武组部分web题解
查看JS,在JS中找到p14.php,直接copy下来console执行,输入战队的token就可以了 js_on 顺手输入一个 admin admin,看到下面的信息 欢迎admin这里是你的信息: ...
- 蒲公英 · JELLY技术周刊 Vol.08 -- 技术周刊 · npm install -g typescript@3.9.3
登高远眺 沧海拾遗,积跬步以至千里 基础技术 官宣: Typescript 3.9 正式发布 TypeScript 3.9 正式发布,这个版本主要聚焦于性能.改进某些特性和提升稳定性.编译器效率在这一 ...
- CEF 与 QML 类比
Qt平台+QML(+QtQuick)+JS = CEF平台+HTML5(+JQueryUI)+JS 运行平台(容器): QT CEF 容器widgets: QtWidgets cef-views 语言 ...
- 获取数据库连接的方式 & Statement操作数据库的弊端
1.获取数据库连接的方式 TestConnection package com.aff.connection; import java.io.InputStream; import java.sql. ...
- parrot os安装vmware pro
转载https://www.linuxtechi.com/install-vmware-workstation-14-debian-9/ Open the terminal and execute t ...
- Rocket - config - Configs
https://mp.weixin.qq.com/s/z2gUYuYQAHQCa_5HZcBszw 介绍各个配置项的组织方式. 参考链接: https://docs.qq.com/sheet/ ...
- Java实现 蓝桥杯 算法训练 Airport Configuration
试题 算法训练 Airport Configuration 问题描述 ACM机场是一个本地机场,对于大多数人来说,机场不是他们的终点或起点,而是中转站.机场有一个规划图.到达的大门在机场的北边(相当于 ...
- (Java实现) 删数问题
删数问题(需知道的数学定理) 给定n位正整数a,去掉其中任意k≤n 个数字后,剩下的数字按原次序排列组成一个新 的正整数.对于给定的n位正整数a和正整数 k,设计一个算法找出剩下数字组成的新数最 小的 ...
- Java实现 蓝桥杯VIP 算法训练 P1102
定义一个学生结构体类型student,包括4个字段,姓名.性别.年龄和成绩.然后在主函数中定义一个结构体数组(长度不超过1000), 并输入每个元素的值,程序使用冒泡排序法将学生按照成绩从小到大的顺序 ...