第一章 对象导论
面向对象语言的基本特性:
1.万物皆为对象。
2.程序是对象的集合,它们通过发送消息来告知彼此所要做的。
3.每个对象都有自己的由其他对象所构成的存储。换句话说,可以通过创建包含现有对象的包的方式来创建新类型的对象。因此,可以在程序中构建复杂的体系,同时将其复杂性隐藏在对象的简单性背后。
4.每个对象都拥有其类型。
5.某一特定类型的所有对象都可以接收同样的消息。
1.3 每个对象提供服务
将对象作为服务提供者可以帮助开发和理解一个程序设计,切有助于提高对象的内聚性。高内聚是软件计的基本质量要求之一。
1.4 被隐藏的具体实现
在任何相互关系中,具有关系所涉及的各方都遵守的边界是十分重要的事情,因此必须要有访问控制。访问控制的第一个存在原因就是让客户端程序员无法触及他们不应该触及的部分;访问控制的第二个存在原因就是允许库设计者可以改变类内部的工作方式而不用担心会影响到客户端程序员。
Java用三个关键字在类的内部设定边界:public、private、protected(默认default)。
1.5 复用具体实现
最简单地复用某个类的方式就是直接使用该类的一个对象,此外也可以将那个类的一个对象置于某个新的类中。我们称其为“创建一个成员对象”。新的类可以由任意数量、任意类型的其他对象以任意可以实现新的类中想要的功能的方式所组成。因为是在使用现有的类合成新的类,所以这种概念被称为组合(composition),如果组合是动态发生的,那么它通常被称为聚(aggregation)。组合带来了极大的灵活性。优先考虑组合,而不是继承。
1.6 继承
一个基类型包含其所有导出类型所共享的特性和行为。可以创建一个基类型来表示系统中某些对象的核心概念,从基类型中导出其他类型,来表示此核心可以被实现的各种不同方式。
所有可以发送给基类对象的消息同时也可以发送给导出类对象。由于通过发送给类的消息的类型可知类的类型,所以这也就意味着导出类与基类具有相同的类型。
有两种方法可以使基类与导出类产生差异。第一种方法非常直接:直接在导出类中添加新方法。但并非总需如此。第二种也是更重要的一种使导出类和基类之间产生差异的方法是改变现有基类的方法的行为,这被称之为覆盖(overriding)那个方法。
“是一个”与“像是一个”的关系
- “是一个”(is-a)
- 继承应该只覆盖基类的方法(而并不添加在基类中没有的新方法)
- 结果可以用一个导出类对象来完全替代一个基类对象。这可以被视为纯粹替代,通常称之为替代原则。
- “像是一个” (is-like-a)
- 有时必须在导出类型中添加新的接口元素,这样也就扩展了接口。
1.7 伴随多态的可互换对象
在处理类型的层次结构时,经常想把一个对象不当作它所属的特定类型来对待,而是将其当作其基类的对象来对待。可以编写不依赖特定类型的代码。
前期绑定
一个非面向对象编程的编译器产生的函数调用会引起所谓的前期绑定,意味着编译器将产生对一个具体函数名字的调用,而运行时将这个调用解析到将要被执行的代码的绝对地址。
后期绑定
面向对象程序设计语言使用了后期绑定的概念。当向对象发送消息时,被调用的代码直到运行时才能确定。编译器确保被调用方法的存在,并对调用参数和返回值执行类型检查(无法提供此类保证的语言被称为是弱类型的),但是并不知道将被执行的确切代码。Java使用一小段特殊的代码来替代绝对地址调用。这段代码使用在对象中存储的信息来计算方法体的地址。
向上转型
通常基类在顶部,而导出类在其下部散开。因此,转型为一个基类就是在继承图中向上移动(导出类转换为基类),即“向上转型”(如图所示)。
1.8 单根继承结构
所有类最终都继承自单一的基类——Object
在单根继承结构中的所有对象都具有一个共用接口,所以它们归根到底都是相同的基本类型。
单根继承结构好处
- 单根继承结构保证所有对象都具备某些功能;
- 单根继承结构使垃圾回收器的实现变得容易得多;
- 极大的简化参数传递;
- 给编程带来了更大的灵活性。
1.9 容器(集合)
- List(用于有序存储)
- Map(关联数组,用于建立对象之间的关联)
- Set(每种对象类型只持有一个)
- …(队列、树、堆栈)
参数化类型(泛型)
向下转型
1.10 对象的创建和生命周期
Java(动态内存分配)
- “垃圾回收”机制(避免暗藏的内存泄漏问题)
1.11 异常处理:处理错误
异常不能被忽略,必须处理。
异常处理不是面向对象的特征。
1.12 并发编程
-
线程只是一种为单一处理器分配执行时间的手段。
-
多个线程访问共享资源必须加锁。