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 ...
随机推荐
- 【Java_SSM】(二)使用eclipse创建一个Maven web工程
这篇博文我们介绍一下如何利用eclipse创件一个maven web工程. (1)File--New--Other--Maven--Maven project 此处我们快速创建一个maven工程 点击 ...
- 【pyecharts】地图显示不全
官网给的解释如下: 自从 0.3.2 开始,为了缩减项目本身的体积以及维持 pyecharts 项目的轻量化运行,pyecharts 将不再自带地图 js 文件. 如用户需要用到地图图表,可自行安装对 ...
- lin-cms-dotnetcore.是如何方法级别的权限控制的?
方法级别的权限控制(API级别) Lin的定位在于实现一整套 CMS的解决方案,它是一个设计方案,提供了不同的后端,不同的前端,而且也支持不同的数据库 目前官方团队维护 lin-cms-vue,lin ...
- vue使用IntersectionObserver实现无限下拉信息流
基于 IntersectionObserver 异步监听方法,实现无线信息流下拉加载, https://developer.mozilla.org/zh-CN/docs/Web/API/Interse ...
- 配置单机Kafka
配置单机kafka 关闭selinux,开启防火墙9092端口 1.关闭selinux vi /etc/selinux/config #SELINUX=enforcing #注释掉 #SELINUXT ...
- strlen 老瓶装新酒
前言 - strlen 概述 无意间扫到 glibc strlen.c 中代码, 久久不能忘怀. 在一无所知的编程生涯中又记起点点滴滴: 编程可不是儿戏 ❀, 有些难, 也有些不舍. 随轨迹一同重温, ...
- python基本操作-文件、目录及路径
目录 1 前言 2 文件夹操作 2.1 查询操作 2.2 创建操作 2.3 删除操作 2.4 修改操作 3 文件操作 3.1 查询操作 3.2 创建操作 3.3 修改操作 3.4 删除 4 路径操作 ...
- CVE-2017-9993 FFMpeg漏洞利用
漏洞原理: 更改连接直接发送请求,造成ssrf 漏洞利用: 脚本地址:https://github.com/neex/ffmpeg-avi-m3u-xbin 用法: 生成一个读取/etc/passwd ...
- Salesforce LWC学习(十七) 前端知识之 onclick & onblur & onmousedown
在Salesforce LWC学习(八) Look Up组件实现篇中,我们实现了公用的lookup组件,使用的过程中,会发现当我们输入内容以后,搜索出来的列表便无法被清空. 针对此种情况我们打算优化一 ...
- python库-collections模块Counter类
Counter类主要是用来跟踪值出现的次数.它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value. demo: all_words = [] # 列表里面是汉字(可 ...