哈工大2022春软件构造学习记录(一)

Lab1实验总结

本次Lab1是我们第一次真正编写完整的java程序,是对java语言的特性和软件构造课程前几讲知识的一个实践,我认为有必要记录下这个过程,包括遇到了什么挑战或困难、如何做到解决实验要求的问题和克服这些遇到的困难,以及在实践中对软件构造课程学到的内容和java语言特性的体悟。当然要写博客记录啦,又不是每次都做的苦难与成就感并存。

一、前言

        由于哈工大本部计算机大类专业的高级语言程序设计课程只讲了c语言,而c语言虽然作为一个学习编程的入门的一个极好的语言,但是是面向过程的(procedure-oriented language),而我们本次软件构造课和实验需要使用的是java语言,java语言作为面向对象(Object-Oriented Language)的编程语言,在设计思想上和使用上都与c语言有很大的差别,这就给我们带来了一定的挑战。

        面向对象编程语言:面向对象语言(Object-Oriented Language)是一类以对象作为基本程序结构单位的程序设计语言,指用于描述的设计是以对象为核心,而对象是程序运行时刻的基本成分。

面向对象语言刻画客观系统较为自然,便于软件扩充与复用。有四个主要特点:

(1)识认性,系统中的基本构件可识认为一组可识别的离散对象;

(2)类别性,系统具有相同数据结构与行为的所有对象可组成一类;

(3)多态性,对象具有唯一的静态类型和多个可能的动态类型;

(4)继承性,在基本层次关系的不同类中共享数据和操作。

其中,前三者为基础,继承是特色。四者(有时再加上动态绑定)结合使用,体现出面向对象语言的表达能力。

       在简单了解java语言的面向对象特性和基本编程方法后,我们就要开始着手解决实验中提出的一些问题了。

二、版本控制系统GIt

        在阅读实验指导书时,我们可以看到实验中需要我们对版本进行管理,这就要求我们学习git工具的配置和使用方法。

        实际上,版本控制也是在软件构造课堂上提到过的重要内容。

        首先,为什么要进行版本控制?在软件开发过程中,往往要遵循一定的开发模式,例如增量过程、原型过程、螺旋过程、敏捷开发等等。大型软件的开发,并不是一蹴而就的,往往需要通过多次的迭代,这就意味着不能够只用一个项目从头到尾在上面去写、去改而得到需要的软件,而是通过软件配置管理和版本控制的方式来实现它。

        简单介绍一下软件配置管理和版本控制:

        软件配置管理:追踪和控制软件的变化。

        软件配置项(SCI):软件中发生变化的最小单元。

        基线:软件变化过程中的“稳定时刻”。

        为了存储各配置项随时间变化的信息和基线信息,就有一个数据库来管理这些内容,即配置管理数据库(CMDB)。

VCS分为三种:

①本地版本控制系统:仓库存储在本地开发系统,无法合作和共享;

②集中式版本控制系统:仓库存储在独立的服务器上,支持多开发者之间的合作,但没办法抵抗服务器崩溃导致无法开发的风险;

③分布式版本控制系统:仓库存储于在每个开发者的本地机器+独立的服务器。

        而我们使用的git,就是当下最常用的分布式版本控制系统之一。其实在大一的时候或多或少就听过git这个东西,隐约中似乎知道这几乎是一个程序员所必备的工具,但是并不真正明白它的作用在哪里,通过这次的实验,我们真正对git和版本控制有了一个明确的认识。

        关于git的工作原理和使用方法,在课堂上有所介绍,在做实验的时候我也上网查找了一些资料,可以总结如下:

        Git实际上是分为四个部分或者叫区域:工作区、暂存区、本地仓库、远程仓库,了解这几个区域会大大帮助我们学习git命令。

        工作区(工作目录)是本地的文件系统,暂存区作为一个工作目录和git本地仓库的隔离区。通常一个纳入版本控制的文件将有以下几个状态:已修改、已暂存、已提交。在本地文件目录建立了仓库后(git init),我们需要跟踪一个文件(git add),也就是把这个文件放到了暂存区,得到了一个满意的修改后把这个暂存了的文件提交到本地仓库(git commit),并且可以进一步地把他提交(git push)到github服务器上,这样一个简单的git使用流程就完毕了。

 下面列出一些常用的git指令以供参考:

//查看某个命令文档
git help <command>
git <command> -h
git <command> --help
//初始化仓库
git init
//对状态的跟踪
git status
//添加文件内容到暂存区(同时文件被跟踪)
git add
//添加所有文件
git add .
//删除
git rm --cached :仅从暂存区删除
git rm :从暂存区与工作目录同时删除
git rm $(git ls-files --deleted):删除所有被跟踪,但是在工作目录被删除的文件
//提交
git -commit -m 'first commit' //从暂存区提交 -m:注释
git commit -a -m 'full commit'从工作区提交
git log //查看提交历史记录
git log --online

git diff //工作区与暂存区的差异
git diff  --cached [<reference>]//暂存区与某次提交的差异,默认为HEAD
git diff  [<reference>]//工作区与某次提交的差异,默认为HEAD

git checkout -- <file> //将文件内容从暂存区复制到工作目录

//撤销暂存区内容
git reset HEAD <file> //将文件内容从上次提交复制到缓存区
git checkout HEAD -- <file> //将内容从上次提交复制到工作目录
//建仓库
git init ~/git-server --bare  //初始化一个本地的远程服务器
//远程
git push //将本地历史推送到远程
git remote add  origin ~/git-server //添加一个远程仓库的别名
git remote -v //查看远程仓库信息
git clone //克隆一个远程仓库作为本地仓库

        还有一些git命令本次实验没有涉及,不再列出,建议大家如果想细致学习git,可以到这个网站学习廖雪峰git教程:https://www.liaoxuefeng.com/wiki/896043488029600/896067008724000

        摘录一段git的工作原理和优点:git的存储结构是一张有向无环图,每次commit在图上会增加一个新的节点,并将HEAD指向这个节点。通常一个子节点有一个父节点,当一个父节点有多个子节点时表明创建了分支,一个子节点有多个父节点时表明进行分支合并。

        git单个节点的存储的信息是文件信息指针tree、作者信息author、提交者信息commiter,而在每个tree中,包含所有文件的信息,对于每个文件指针,如果文件变化了,则指向变化后的新文件,如果没有变化,则指向上次提交的文件,不做重复存储。

        传统VCS存储的是文件每个版本之间的变化,这种办法的优点是存储空间较小,但由于存储的只是变化,取出指定时期的文件要先取出原文件,再取出变化内容,最后做合并形成新文件,所以取出文件的时间复杂度较高。git存储的则是文件,所以取出特定版本的文件比较方便,但是代价的是空间复杂度较高。

        关于分支的合并:对于合并操作来说,如果是把一个做了更改的分支合并到一个未作更改的分支,那么就将未作更改的分支的指针移到做过更改分支的指针的位置。

        在实验过程中遇到的问题主要就是github半墙状态,所以push这一步给我增添了很多不必要的麻烦,比如网络问题,还有连接远程仓库时登录问题等等,这些最终都通过善用百度和csdn解决了。

三、对异常输入情况的处理方式

        本次实验中让我印象很深刻的就是对异常输入的处理这部分,也对应着课程中代码健壮性这一问题。关于这个问题,在后来学了规约之后,我又再次进行了思考。虽然有时可以通过规约的方式限制client的输入合法,但是我们仍然不能让我们的代码不对这些输入的错误不做任何处理或反应,这是不安全的,甚至可能造成程序崩溃。

        我们处理这种异常输入的方法,在接触java以前通常是这样的:使用if等语句判断是否满足对输入限制的条件,如果不满足,在控制台输出一个提示语句后选择等待重新输入或者退出程序。这说明在学习和使用c语言编程时我们就多少已经养成了一些处理异常输入增强程序健壮性的习惯。

        而在java语言中,特别提供了一种解决这个问题的机制,就是异常。

常见的异常类包括:

1、空指针异常类:     NullPointerException

2、数据类型转换异常:ClassCastException

3、没有访问权限:IllegalAccessException

4、方法的参数错误:IllegalArgumentException

5、数组下标越界异常:IndexOutOfBoundsException

6、文件已结束异常:EOFException

7、文件未找到异常:FileNotFoundException

8、字符串转换为数字异常:NumberFormatException

9、指定的类不存在: ClassNotFoundException

10、实例化异常:InstantiationException

11、运行时异常:RuntimeException,上面的很多异常都是这个异常的子类

       如何把异常处理机制和我们的实验要求结合起来?
       在有可能出现异常输入的地方,例如MagicSquare中需要把字符串转为Integer(int),这时可能有的字符串不是整型数形式仍然传到了Integer.parseInt方法中作为参数,这时虚拟机会抛出一个NumberFormatException,我们可以使用try-catch语句,在try中捕获这个异常,并在catch中定义我们的处理代码,例如输出提示退出,或者直接抛出异常并附带提示语句等等。

下面是一个例子:

try {
	for(String string:str) {
		if((val = Integer.parseInt(string))<0) {
			System.out.println("Format Error! Below zero!");
			return false;
		}
		if(i==0) sum += val;
		matrix[i][j++] = val;
		if(j>length) {
			System.out.println("Format Error! Not a matrix!");
			return false;
		}
	}
}catch(NumberFormatException e){
	System.out.println("Format Error! Illegal input!");
	return false;
}

        除此之外,在实验中我们还使用了字符缓冲流这些,是需要关闭的。如果抛出异常并退出,这些流可能就不会关闭。如何解决这个问题?其实可以使用try-catch-finally语句,将close写在finally中,它就一定会被执行。

try {
	bw = new BufferedWriter(new FileWriter(file));
	for (i = 1; i <= square; i++) {
		magic[row][col] = i; 			//往矩阵里写入的值每次增加1
		if (i % n == 0)					//每写n个数让行数加1
			row++; 
		else {
			if (row == 0) 			//行数为0的时候下一次写最后一行,否则下次写这行的上一行
				row = n - 1;
			else
				row--;
			if (col == (n-1)) 	//这次写最后一列的时候下一次写第0列,否则下一次写这次的下一列
				col=0;
			else
				col++; 
		}
	}
	for (i = 0; i < n; i++) { 					//加上文件写入
		for (j = 0; j < n; j++) {
			System.out.print(magic[i][j] + "\t"); 
			bw.write(magic[i][j] + "\t");
		}
		System.out.println();
		bw.write("\n");
	}
} catch (IOException e) {
	// TODO Auto-generated catch block
	System.out.println("Fail to write to the file!");
	return false;
}finally {
	try {
		bw.close();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		return false;
	}
}

四、java常用数据结构

        本次实验中还有一个特别的地方就是使用了java的一些数据结构,List、Set、Map等。我们可以选择这几个接口的特定实现类,直接使用他们的一些内置方法,实现很多操作,这也是与c语言非常不同的一点,大大提高了编程的效率。这些方法的特点是我们不需要了解它们的具体实现,只需要按照规约要求使用即可。

        这几个数据结构的使用方法还是比较简单易学的,关键是什么时候使用、怎么用这几个数据结构实现一些更复杂的数据结构。本次实验的P3要求建立一个图,可以用Map实现,也可以用多个Set或者List来实现,这个设计的过程需要一点点思考。


以上就是在本次软件构造实验一过程中的一些心得体会,如有错误敬请指正。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值