Java7基础教程 Jay Bryant著 李鹏 韩智译
这本书大概看了一个星期吧,比较基础的一本书,老外写的书一般要更容易懂一些。这本书印象最深的还是里面的电子游戏吧,比较经典,也比较有意思。印象最好的是里面的代码都是已经调通了的,不像有些书里面虽然也附加了源代码,但是很多都是没有调通的。老外还是比较靠谱的。
下面写一写这本书的概要,算是记录一下吧。(常常写记录真的是一个好习惯,哈哈。)
想要编写Java程序,就需要Java开发包(Java Development Kit,JDK)。严格来说,JDK就是唯一所需。然而,有些其他工具可以使得编写Java程序更容易一些。大多数开发人员都喜欢使用集成开发环境(Integrated Development Environment,IDE),Eclipse便是其中最受欢迎的一种。
Java7的API文档网址是:http://docs.oracle.com/javase/7/docs/api/。
第一章:编写第一个Java程序。
这章主要是讲安装JDK和Eclipse。有一个常用的知识点,时间格式转换,记录一下:
//首先创建一个Date对象,以获取从1970年1月1日以来的秒数
Date now = new Date();
//第二步,创建一个表示格式的对象
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//第三步,对date对象应用格式
String formatteredDate = formatter.format(now);
第二章:Java语法
(1)Java中的语法大部分来自C++语言,而C++的语法则多是源自C。
(2)80个字符通常作为一行代码的上限,如果代码达到80个字符尝试将其分成两行,80个字符的长度限制源于每行记录80个字符的打孔卡。
(3)接口提供一种便利的方式,确保相似的类实现相似(没必要一模一样)的行为。假设我们为动物王国建模,则模型会对应一组类。这样的模型可能有一个Predator(食肉动物)接口,其中有一个hunt(捕猎)的方法。猫和狗都有hunt()方法,但是它们的具体猎取方式有差别(猫喜欢猛扑,狗喜欢追捕)。抛开类的具体细节,Predator接口让我们知道食肉动物都有捕猎的特点,但具体到每一种动物,它们的捕猎行为又有自己的特点。
Java支持abstract关键字,有abstract修饰的类、方法或者字段等不能实例化,也就是说,不能创建。至于接口,实现接口的类必须实现接口的方法,接口什么都不实现。此外,接口以及它包含的方法总是静态类型的。因此,每一个接口(以及它的方法)只能在系统里存在一份。
(4)静态代码块。 静态代码块会自动被每一个构造方法所调用
private String name;
static{
name = "Java7";
}
假设某个类有10个值需要设置,有4个构造方法,那么静态代码块就可以大显身手,可以节省空间。此外,静态代码块的真正价值在与确保那些需要初始化的字段都能被构造方法间接 设置。如果有字段在一些构造方法里设置,而在另外一些构造方法里没有设置,可能会导致bug。
第三章 数据类型
(1)整型数据 byte(8位) short(16位) int(32位)long(64位) BigInteger。BigInteger类可以表示任意大小,但是运行速度慢。
(2)实型数据 float(32位) double(64位) BigDecimal。BigDecimal类可以表示比double所能表示的数还大的数,但是运行速度慢。float a = 12.34f,一定要加f。double后面可以不加d,因为默认的浮点数的类型就是double。
(3)布尔型数据 boolean(true or false)
(4)字符型数据 char(16位) 代表一个字符,实际保存时用的是无符号的16位整型数据,所能表示的最小值是0,最大值是65536。然而,不要用char来保存数字。
(5)特殊的数据类型:字符串
(6)类型转换。int->String:String myIntString = Integer.toString(1);
String->int:int myStringInt = Integer.parseInt("123");
int->用字符串表示的二进制:String myIntBinary = Integer.toBinaryString(123);
(7)不存在的类型:null。null引用的是一个不存在的对象。
(8)枚举enum public enum Direction{
NORTH, EAST, SOUTH,WEST;
}
可以转化为常量:public static final int NORTH = 0; 枚举和常量的区别是:常量可以和int做比较,而在实践中是不提倡这么做的。比如枚举值Direction.NORTH是不能当做整型数据使用的。
每一个enum实际都是一个类,它的声明语法和类很相似。
public enum DirectionEnum{
NORTH (0),
EAST(90),
SOUTH(180),
WEST(270);
private final int degree;
DirectionEnum(int degree){
this.degree = degree;
}
public int getDegree(){
return this.degree;
}
};
public static void main(String[] args) {
for(DirectionEnum d : DirectionEnum.values()){
System.out.println(d + " is " + d.getDegree() + " degrees.");
}
}
//NORTH is 0 degrees.
//EAST is 90 degrees.
//SOUTH is 180 degrees.
//WEST is 270 degrees.
第四章 Java运算符
(1)~按位取反,对整数值的每一位逐步取反。在应用按位取反运算符之前,Java会把byte、short以及char变量的值提升成32位,运算符的结果是一个int型的数据。
例如:byte a = 0;
Byte b = new Byte(a);//没问题
Byte c = new Byte(~a); //编译通不过,因为Byte的构造方法不能接受int型参数
int d = ~a; //OK
(2)移位运算。 >>右移运算符 <<左移运算符
(3)按位与& 按位或| 按位异或^
第五章 流程控制、循环以及分支
(1)do-while循环,在实际的开发中我是很少用到do-while循环的,do-while循环是先检测循环代码块再检测循环条件的,在实际开发中还是有实用价值的。比如先尝试连接一次服务器或者数据库再检测循环条件。
(2)break和continue。break会跳出它外层的循环,而continue仅仅是停止当前的循环迭代,并开始进行下一次循环。
第六章 面向对象编程
(1)多重继承。Java不支持多重继承,而其他语言(比如C++)支持多重继承。多重继承的问题是一个类有两个父类,而这两个父类可能是由同一个祖先类扩展而来的,你的代码如何知道哪一个祖先类提供了需要的信息?这种现象有时被称做”钻石型问题“。因为如果用图形表示的话,看起来像一颗钻石的形状。
(2)抽象类。抽象类是永远不会实例化的类,也就是说,这个类没有对象与之关联。这样的类通常是作为其他类的基类。比如说Mammal类,现实中所有的哺乳动物都是具体的哺乳动物,而不是抽象的哺乳动物。所以可以将Mammal类定义为抽象类,而Cat、Dog以及Mouse等扩展自Mammal类(因为猫、狗以及老鼠都是哺乳动物)。
(3)抽象方法。抽象类可以有抽象方法,如果要扩展这种含有抽象方法的类,在子类里必须实现这个抽象方法。
(4)静态字段仅有一个实例,为该类的所有实例化对象所共有。
静态字段也叫做类字段,因为它仅适用于类,不适用于该类所创建的对象。
所有的静态字段通常应当是private类型的。
(5)静态方法意味着系统里只能有一个这样的方法,不管这个类生成了多少个对象。
(6)静态代码便于定义一段代码,这段代码会自动地被每一个构造方法所用。
1 private static String name; 2 static{ 3 name = "staticBlockClass"; 4 }
(7)传值和引用。比如将一个int参数传递给方法,方法接收到的是这个int的副本,也就是有2个int的变量,在方法中修改副本的值不会影响原来int的值。
而将一个对象传递给方法是将指针传递给方法,在方法中改变对象的某些属性值会影响原来的对象。
第七章 开发用户界面
这一章没什么特别好记录的,主要讲述的是用户界面组件Java Swing,有一个比较经典的游戏——扫雷,自己动手敲了下代码。
第八章 读写文件
在实际开发中,读写文件还是比较常用的。
(1)在表示文件路径的时候,使用反斜杠不如使用File.separator。
(2)创建空文件。
1 String fileName = "D:" + File.separator + "file" + File.separator + "testFile.txt"; 2 File myFile = new File(fileName); 3 try { 4 myFile.createNewFile(); 5 } catch (IOException e) { 6 System.out.println("Could not create " + myFile.getPath()); 7 }
(3)文件内容的写入。
1 String readFileName = "D:" + File.separator + "file" + File.separator + "read.txt"; 2 String writeFileName = "D:" + File.separator + "file"; 3 File file = new File(writeFileName); 4 if(!file.exists()){ 5 file.mkdirs(); 6 } 7 8 try { 9 FileInputStream fin = new FileInputStream(readFileName); 10 FileOutputStream fout = new FileOutputStream(writeFileName + File.separator + "write.txt"); 11 12 int length = 0; 13 byte[] b = new byte[1024]; 14 15 try { 16 while((length = fin.read(b)) > 0){ 17 fout.write(b, 0, length); 18 } 19 } catch (IOException e) { 20 System.out.println("读取文件出错!"); 21 } 22 23 try { 24 fin.close(); 25 fout.close(); 26 } catch (IOException e) { 27 System.out.println("关闭文件出错!"); 28 } 29 30 31 } catch (FileNotFoundException e) { 32 System.out.println("找不到文件!"); 33 }
(4)追加文件内容而不是替换文件内容
FileOutputStream fout = new FileOutputStream(writeFileName + File.separator + "write.txt", true);
第九章 读写XML
这章我没怎么看懂,可能是因为平时接触XML文件的机会比较少,所以对XML没什么感觉。以后有机会接触XML再来补充一下内容吧。
第十章 动画
这章比较有意思,都是动画,自己也动手敲了一下。
第十一章 用Eclipse调试程序
这章主要是讲调试方法的,不过平时我还是比较喜欢用输出来调试程序。
第十二章 电子游戏
这章主要是讲游戏,自己动手敲了下代码。
第十三章 垃圾回收
这章算是比较重要的,但是是比较理论性的东西,不太好形象的理解。
(1)当使用其他许多编程语言(包括C++)的时候,程序员需要自己管理内存,通过编写代码,在恰当的时候将对象从内存中释放。Java使得程序员无需自己管理内存。
(2)Java虚拟机JVM(Java Virtual Machine)如何分配内存的问题:每一次创建一个新对象或者基本数据类型变量的时候,堆内存的使用量就增长一点,增长量就是新创建的对象或者基本数据类型变量的大小。此外,如果创建的是一个复杂的对象(对象自身还包括一些其他的对象),堆内存的增长量就是这些对象的大小的总和。
(3)垃圾回收的主要规则是:如果某对象不再被其他对象所引用,它就会被作为垃圾被回收。换句话说,一旦某对象不被任何对象使用,这个对象就做好了从内存中被移除的准备。另外一种说法是:这样的对象不可访问,也就意味着没有代码能访问这个对象了。
(4)Java垃圾回收算法:标记清除法
Java使用的垃圾回收算法叫做标记清除法。从理论上说,这个算法很简单。首先,在第一阶段标记任何可以回收的内存。然后,在第二阶段遍历所有的内存,并释放第一步标记的内存。
然而在实践中,这个过程要复杂的多。基本的标记清除算法工作得不错,只是当垃圾回收运行的时候,整个程序要停止运行。这样,Java就很不适合实时监控等领域。
为解决这些问题,Java设计者研究出了更为高级的算法:增量垃圾回收算法和并发垃圾回收算法。
- 增量垃圾回收依赖于程序和垃圾回收器的间歇性停止和启动(垃圾回收器是JVM里和程序并行运行的特殊程序)。JVM先让程序执行一些代码,然后垃圾回收器做对象清除的工作,如此反复。这种情况下,程序执行的时 候,垃圾回收器也在执行。可以想象的到,程序的性能仍然要慢于不使用垃圾回收器的情况。实际上,Java的各个版本都存在垃圾回收器工作时程序性能明显降低的问题。
- 并发垃圾回收器能够让程序几乎以全速运行,不过有一个例外:当扫面栈(Stack, 内存中对象的列表)的时候,程序必须停止下来。幸好扫描栈内存花费的时间很少。扫描栈(仅仅是一个列表而已)的时间要比扫描堆(heap, 内 存中所有的对象)的时间少多了。想象一下,阅读一本书的目录和阅读一本书的全部正文所有的时间差异。
- 并发垃圾回收器是如何让程序几乎以全速运行的呢?垃圾回收器自身不关注如何找到所有可以回收的对象,取而代之的是,它仅找出那些确信不再使用的对象,并释放这些对象所占用的内存。在下一次的扫描周期里,它可以捕获到任何漏掉的,以及两次扫描周期之间变得可以移除的那些对象。因此,虽然并发垃圾回收器的每一次清除并不彻底,但是它可以让程序运行得更平滑一下。
- Java1.4.2支持四种垃圾回收机制:有两种是基本垃圾回收机制的变种、增量垃圾回收机制以及并发垃圾回收机制。软件开发人员可以决定(最好经过测试)哪一种垃圾回收机制更适用于自己的程序。
- Java5(也就是Java1.5)和Java6(Java1.6)持续改进、通过设置垃圾回收的一些开关选项,提供了对垃圾回收的微调功能。
- Java7提供了一种新型的垃圾回收器,叫做G1(即garbage first)。G1垃圾回收器的改进在于它把堆内存划分为若干区域。回收的时候是从拥有最多垃圾的那个区域开始,逐个检查每一个区域。如果由于程序运行的需要,G1还不能清除所有区域,至少有机会清理垃圾最多的那个区域。在后续的清除中,其他的区域逐步地填充,变成包含了最多垃圾的区域。然后G1逐个清除这些区域。这样优化比较好的地方在于,我们并不需要专门作任何新的设置以控制垃圾回收工作。
第十四章 递归
很多时候我会将递归转换成其他方法来实现。递归难以控制和操作。但是递归还是有自己的独到之处的,递归其实是人类语言的基本特征。
第十五章 泛型和正则表达式
(1)泛型。在泛型说明符的语法中使用尖括号”<“和”>“。
创建一个带有泛型说明符的集合,这样可以防止把不期望的对象类型添加到集合里。
LinkedList<JPanel> panelList = new LinkedList<JPanel>();
(2)正则表达式
Java正则表达式的元字符
()用以表示一个子模式。compan(y|ies)可以匹配company和companies。另外还可以定义一个组,例如,(Dog)把Dog这3个字符视为一个整体。
[ ] 用以表示一组字符。例如:[A-Z]能匹配任何大写字符,A[A-Z]能匹配”AAZ“、”ABZ“、......、”AZZ“
{ }用以表示匹配特定数量的字符。例如:s{3}能匹配3个s字符:sss。Par{3}能匹配"Parsss"
\ 表示转义序列的开始。如果需要匹配.,则可以使用\.。如果需要匹配\,则可以使用\\
^ 表示匹配字符串的开始。^A可以找出以A开始行。在范围表达式内部,^表示否,[^abc]是指任何a、b或者c以外的字符。
$ 表示匹配字符串的结束。Z$匹配以Z结束的字符串。
| 匹配位于该符号两侧的表达式。this|that可以匹配”this“或者”that“
? 最多匹配一次前面的字符。例如:ban?可以匹配”ba“和”ban“
* 匹配该字符前面的那个字符任意次数(包括0次)。例如:ban*可以匹配”ba”、“ban”、“bann”、“bannn”等
+ 匹配某字符一次或者多次。
. 匹配任何单个字符。例如:bar.匹配“bark”、“bard”、“bar9”等。.*匹配任意数量的任意字符。
就记录比较常用的这些吧,累了。