20155303 2016-2017-2 《Java程序设计》第六周学习总结

20155303 2016-2017-2 《Java程序设计》第六周学习总结

课堂笔记

  • 高效学习法推荐

看视频学习(2h)→ 以代码为中心看课本,思考运行结果并验证(3h)→ 课后作业验证(5h)→ 教材指导

【充分利用教材指导,积极思考遇到的问题,在实践中学习,不要拘泥于记忆教材讲解的知识点和概念。】

教材学习中的问题和解决过程

  • 『问题一』:以课本P306为例,args[0]args[1]代表什么?

『问题一解决』:java的主方法为:public static void main(String [] args)args[0]表示命令行输入时传的第一个参数,args[1]同理。例如执行以下程序:

运行java WhatIsArgs No1 No2命令可得到结果:No1No2

  • 『问题二』hasNextLine()nextLine()的用法?

『问题二解决』:查询API文档可知,hasNextLine()nextLine()均继承自java.util.Scanner。它们的用法是,hasNextLine()用来判断下一行是否存在,常用在while语句中,当且仅当下一行有输入时返回true;而nextLine()返回值是当前行的剩余内容。

两者具体使用方法可参考以下代码:

  • 『问题三』:课本P316提到“如果在做对象串行化时,对象中某些数据成员不希望被写出,则可以标上transient关键字”一句该如何理解?

『问题三解决』:一个对象只要实现了Serilizable接口,这个对象就可以被序列化,不过有些时候,一个类的有些属性需要序列化,而其他属性不需要被序列化。java的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

比如以下程序:

在上面的例子中,将属性b前添加关键字transient,虽然我们序列化的对象b的属性值为“Transient or not”,但是当我们反序列化之后发现这个属性为空,说明这个属性没有进行序列化。

【关于什么是序列化,参考博客深入理解Java对象序列化

  • 『问题四』:守护线程与非守护线程

『问题四解决』:简单来说,java可以创建两种线程,即守护线程与非守护线程。非守护线程(User Thread用户线程)就是平时创建的一般线程,而守护线程(Daemon Thread守护线程)是用来服务用户线程的。

区分守护线程与非守护线程:当线程只剩下守护线程的时候,JVM就会退出.但是如果还有其他的任意一个用户线程还在,JVM就不会退出。

setDaemon()与isDaemon()setDaemon方法用来设定一个线程。如果setDaemon(true)表示设定一个线程为Daemon线程。isDaemon则用来测试一个线程是否为守护线程。如果是,返回true。

  • 『问题五』:Thread常用方法以及状态图

『问题五解决』

常用方法:

start(); //启动线程

getId(); //获得线程ID

getName(); //获得线程名字

getPriority(); //获得优先权

isAlive(); //判断线程是否活动

isDaemon(); //判断是否守护线程

getState(); //获得线程状态

sleep(long mill); //休眠线程

join(); //等待线程结束

yield(); //放弃cpu使用权利

interrupt(); //中断线程

currentThread(); //获得正在执行的线程对象

Thread状态图:

  • 『问题六』:对于课本P334join()的介绍产生疑问:Thread B 什么时候加入主线程呢?是不是从join()方法出现的位置开始呢?

『问题六解决』:在不同位置调用join()方法,程序如下:

“尝试一”运行结果:

“尝试二”运行结果:

可以看出,程序启动后主线程就开始了,调用join()之后把Thread B加入主线程流程中,执行完毕后再继续执行原本的线程。

注:可以在join()指定时间,如join(1000)表示让加入的线程执行1000毫秒,也就是1秒。1秒结束后线程可以继续执行原本流程。

代码调试中的问题和解决过程

本周跟视频学习的过程中思考一个问题:字节流和字符流的优势各在哪里呢?使用哪一个比较好呢?

答案是字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输和保存的,包括图片,mp3等等。但是字符只是在内存中才会形成,所以在开发过程中,字节流使用更加广泛。

下面通过几个例子总结了字节流的应用情况。

  • 『问题一』:向文件中写入字符串

运行以下程序:

查看hello.txt会看到“你好”:

也可以向文件中一个字节一个字节地写入字符串,运行结果同上:

  • 『问题二』:向文件中追加新内容

运行以下程序:

查看hello.txt会看到“你好DiWeijia”:

  • 『问题三』:读取文件内容

运行以下程序,可以读出hello.txt里的内容:

知识拓展

谢涛老师在之前的一篇博客中提出问题:如何把一个Java源文件里的注释去掉(处理结果可以输出到新的文件里),保证修改后源文件仍然能正常编译,正确运行。得到娄老师的指点之后,明白这个问题的解决需要用到正则表达式

正则表通常被用来检索、替换那些符合某个模式(规则)的文本。我们经常使用Windows/Dos下用于文件查找的通配符(wildcard),也就是* 和?。如果想查找某个目录下所有的word文档,我们会搜索 * .doc。在这里,* 会被解释成任意的字符串。和通配符类似,正则表达式也是用来进行文本匹配的工具,只不过比起通配符,它能更精确地描述你的需求。

比如要求填写5-12位的QQ号,就可以使用正则表达式:\d{5,12}$。表示匹配字符串的开始,$表示匹配字符串的结束,\d表示匹配数字,{5,12}表示数字为5-12位。这样一来,如果用户输入能匹配这个表达式的话,就符合要求了。

像以上的“^”、“$”等都是正则表达式的元字符。元字符以及常用的正则表达式如下:(参考娄老师博客正则表达式入门

“去注释”问题可以利用正则表达式的相关知识,结合之前学到的“转义符”解决。基本思路是:对待分析的带注释段的字符串进行遍历,声明一个缓冲字符串变量来记录非注释的部分,最后返回这个缓冲字符串变量作为结果。这样就能把去除注释之后的文件保存下来了。可以从以下四个方面考虑:

1.考虑双引号:双引号中的注释部分是不能去掉的,比如print("//Hello"World"/ * comment * /")。以下几条都应在没有双引号的前提下。如果发现了开始双引号,在匹配结束双引号的时候要注意可能会遇到转义双引号,需要跳过以\开始的双引号,从而匹配到正确的结束双引号;

2.考虑 / * comment * / 形式的注释 :当遇到 / * 部分便停止记录,继续往后遍历到 * / 部分,实现跳过 / * * / 段;

3.考虑/ * comment / * inside * / out * /形式的嵌套注释:声明一个数字变量来记录 / * 的开始的次数,遇到一个 / * 就+1,遇到一个 * / 就-1,实现嵌套匹配;

【注意】:注释不能嵌套:/ * / * inside * / * /,所以这种情况不予考虑。感谢谢涛老师的指正:)

4.考虑双斜杠注释 发现 // 形式的字符串的时候表明遇到了双斜杠注释,这时候使用while循环继续向后遍历,直到发现一个换行符,从而跳过整个这一行;

正则表达式的应用领域非常广,以上提到的这些只是一点皮毛。要想熟练掌握正则表达式的用法,还需要多动手多实践。

代码托管

上周考试错题总结

  • 『问题一』

现有:

- list是一个合法的集合引用

- getCollection()返回一个合法集合的引用

哪个是合法的?

A.or(Object o ; list)

√B.for(Object o : getCollection())

C.for(Object o : list.iterator())

D.for(lterator i ; list.iterator() ; i.hasNext () )

√E.for(lterator i=list.iterator(); i.hasNext (); )

  • 『考点』

B选项是增强式for循环。增强式for循环能对数组和集合进行遍历,使用上更加简洁。D选项是普通循环,i操作了iterator()接口,如果没有抛出异常,则i.hasNext()返回值为true。

  • 『问题二』

Which of the following methods will not compile? :

A.

private void method1(String name) {
if (name.equals("star"))
throw new IllegalArgumentException(name);
}

√B.

private void method2(int age) {
if (age > 30)
throw Exception();
}

C.

public double method5() throws Exception {
return 0.7;
}

√D.

protected double method4() throws Exception {
throw new Throwable();
}
  • 『考点』

B选项无法编译,因为Exception是受检异常,必须使用throws声明此方法会抛出的异常类型或父类型。D选项无法编译,因为子类不能抛出比父类更一般的异常。

  • 『问题三』

What is the output of the following code?

class EJava {
void method() {
try {
guru();
return;
} finally {
System.out.println("finally 1");
}
}
void guru() {
System.out.println("guru");
throw new StackOverflowError();
}
public static void main(String args[]) {
EJava var = new EJava();
var.method();
}
}

A.guru

finally 1

√B.guru

finally 1

Exception in thread "main" java.lang.StackOverflowError

C.guru

Exception in thread "main" java.lang.StackOverflowError

D.guru

E.The code fails to compile.

  • 『考点』

首先程序可以通过编译。其次,StackOverflowError()是非受检异常,方法guru()在try-catch块中,异常会被捕捉。由于guru()本身没有处理堆栈溢出错误,但method()定义了finally区块,所以程序在执行完毕finally区块之后将错误传播至JVM,中断程序。

结对及互评

本周结对学习情况

  • 结对同学学号20145202马超

  • 结对学习内容:查看对方代码,并对学习中遇到的疑问进行交流。解答对方博客中未解决的问题。

第六周博客互评情况

其他(感悟、思考等,可选)

  • 1、最近几周的学习内容系统性和连贯性很强,所以要经常查询API文档,了解常用的类和方法以及其继承架构。

  • 2、学习过程中应该把思考作为重中之重,这一点之前就领悟到了,不过在实践之中经常被忽略。所以我们不应该单纯地把代码行数看做衡量自己学习情况的标准,理解得透彻了才能达到举一反三的效果。按照这种方法学习不仅可以深刻理解所学知识,也提高了学习效率,减轻了学习负担。

  • 3、不学则已,一学即专。心不能静下来的时候宁可不看书。万万不可一边打着学习的名义捧书研读,一边还在为其他事困扰,这样只能欺骗自己“我真的学习了”,却仅仅是耗费时间,而达不到理想的效果。

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 16/16 1/1 18/18 初步认识了Java
第二周 219/235 1/2 28/46 学习了Java的基本语法知识
第三周 766/1001 1/3 23/69 了解对象与参考的关系,以及封装的概念与实现
第四周 984/1985 1/4 18/87 学习了继承与多态的关系,以及接口的多态操作
第五周 866/2851 1/5 12/99 学习了异常处理,学会使用Collection收集对象
第六周 664/3515 1/6 15/114 认识字节流和字符流的继承架构,学习线程与并行API

尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。

参考:软件工程软件的估计为什么这么难软件工程 估计方法

  • 计划学习时间:20小时

  • 实际学习时间:15小时

  • 改进情况:这周的效率跟之前比有了很大的提高,我想应该归功于娄老师上节课提到的学习方法。以后的学习应该抓住重点,多思考,不要把时间浪费在照搬书上的代码之类的无用功上。

(有空多看看现代软件工程 课件
软件工程师能力自我评价表
)

参考资料

posted @ 2017-04-02 16:28  0x14b7狄  阅读(557)  评论(8编辑  收藏  举报