Thinking in Java (the 2nd edition) Study Note
第1章 对象入门
Alan Kay总结了Smalltalk的五大基本特征。这是第一种成功的面向对象程序设计语言,也是Java的基础语言。
通过这些特征,我们可理解“纯粹”的面向对象程序设计方法是什么样的:
(1) 所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作。理论上讲,
可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。
(2) 程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那个对象“发送一条消息”。
更具体地讲,可将消息想象为一个调用请求,它调用的是从属于目标对象的一个子例程或函数。
(3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。所以,尽管对象
的概念非常简单,但在程序中却可达到任意高的复杂程度。
(4) 每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实例”。其中,“类”(Class)是“类型”(Type)
的同义词。一个类最重要的特征就是“能将什么消息发给它?”。
(5) 同一类所有对象都能接收相同的消息。这实际是别有含义的一种说法,大家不久便能理解。由于类型为“圆”(Circle)
的一个对象也属于类型为“形状”(Shape)的一个对象,所以一个圆完全能接收形状消息。这意味着可让程序代码统一指挥
“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包括“圆”。这一特性称为对象的“可替换性”,是OOP最重要的概念之一。
第2章 一切都是对象
2.1 用句柄操作对象
创建一个String句柄:
String s;
这里创建的只是句柄,并不是对象。若此时向s发送一条消息,就会获得一个错误(运行期)。这是由于s实际并未与任何
东西连接(即“没有电视机”)。因此,一种更安全的做法是:创建一个句柄时,记住无论如何都进行初始化:
String s = "a";
创建句柄时,我们希望它同一个新对象连接。
通常用new关键字达到这一目的。new的意思是:“把我变成这些对象的一种新类型”。所以在上面的例子中,可以说:
String s = new String("a");
2.2
程序运行时,我们最好对数据保存到什么地方做到心中有数。特别要注意的是内存的分配。有六个地方都可以保存数据:
(1)寄存器
(2)堆栈:驻留于常规RAM(随机访问存储器)区域
可通过它的“堆栈指针”获得处理的直接支持。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。创建程序时,
Java编译器必须准确地知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于它必须生成相应的代码,以便向上
和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些Java数据要保存在堆栈里——特别是对象句柄,但Java
对象并不放到其中。
(3)堆:一种常规用途的内存池(也在RAM区域)
其中保存Java对象。和堆栈不同,“内存堆”或“堆”(Heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储
空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。要求创建一个对象时,
只需用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然会
付出一定的代价:在堆里分配存储空间时会花掉更长的时间
(4)静态存储:这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM里)
程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。Java对象本身永远
都不会置入静态存储空间。
(5)常数存储
常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格地保护,
所以可考虑将它们置入只读存储器(ROM)。
(6)非RAM存储
若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对
象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于固定对象,对象保存在磁盘中。即使
程序中止运行,它们仍可保持自己的状态不变。对于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体中。
一旦需要,甚至能将它们恢复成普通的、基于RAM的对象。Java 1.1提供了对Lightweight persistence的支持。
2.3 对象的作用域
{
String s = new String("a string");
} /* 作用域的终点 */
那么句柄s会在作用域的终点处消失。然而,s指向的String对象依然占据着内存空间。在上面这段代码里,我们没有办法
访问对象,因为指向它的唯一一个句柄已超出了作用域的边界。
2.4 javadoc注释
1. @param
格式如下:
@param 参数名 说明
其中,“参数名”是指参数列表内的标识符,而“说明”代表一些可延续到后续行内的说明文字。一旦遇到一个新文档标记,
就认为前一个说明结束。可使用任意数量的说明,每个参数一个。
2. @return
格式如下:
@return 说明
其中,“说明”是指返回值的含义。它可延续到后面的行内。
3. @exception
违例标记的格式如下:
@exception 完整类名 说明
其中,“完整类名”明确指定了一个违例类的名字,它是在其他某个地方定义好的。而“说明”(同样可以延续到下面的行)
告诉我们为什么这种特殊类型的违例会在方法调用中出现。
4. @deprecated
这是Java 1.1的新特性。该标记用于指出一些旧功能已由改进过的新功能取代。该标记的作用是建议用户不必再使用一种
特定的功能,因为未来改版时可能摒弃这一功能。若将一个方法标记为@deprecated,则使用该方法时会收到编译器的警告。
第3章 控制程序流程
“就象任何有感知的生物一样,程序必须能操纵自己的世界,在执行过程中作出判断与选择。”
3.1 赋值
在为对象“赋值”的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是它的句柄。所以倘若“从一个对象
到另一个对象”赋值,实际就是将句柄从一个地方复制到另一个地方。这意味着假若为对象使用“C=D”,那么C和D最终都会
指向最初只有D才指向的那个对象。
3.2 == 问题
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
//结果是false ,因为比较的是n1和n2的引用(即比较的是指向n1和n2的指针)
每个类都有一个默认的equals()方法,因为Object 就有这样一个方法;所有的类默认继承它,但比较的是引用