第一章 对象导论
1.1 抽象过程
以往的编程语言,汇编,抽象的过程要求我们在解决问题时,基于计算机的结构,而不是基于所要解决问题的结构。所以程序员要建立机器模型和解空间模型之间的关联。
面向对象方式通过向程序员提供问题空间中的元素的工具而更进了一步。这种思想的实质是我们可以通过添加新的对象使得自身适用于某种特定的问题。
JAVA 语言的五个基本特性:
万物皆对象。将对象视为神奇的变量,可以存储数据。抽取问题的任何概念,化为对象。
程序是对象的集合,通过发送消息来告知彼此所要做的。可以将消息视为某个特定对象的方法的调用请求
每个对象都有自己的有其他对象所构成的存储。可以通过穿件包含现有对象的的形式,来创建新的对象(子类)。
每个对象都拥有其类型。每个对象都是某个类的实例。类的特性就是可以发送什么样的消息它。
某一特定类型的所有对象都可以接受同样的消息。子类可以接受任何父类类型的消息传递。可替代性,向上转型。
1.2 每个对象都有接口
类描述了具有相同特性(数据元素)和行为(功能,函数)的对象集合。所以类实际上是一个数据类型。程序员通过类来适应问题,而不用局限于现有固定的类型。通过添加新的数据类型来扩展编程语言。
如何获取有用的对象? 满足某种特性的对象,由接口所定义。接口确定了特定对象所能发出的请求。程序中必须含有并且满足某种需求。这些代码构成了实现。
1.3 每个对象都提供服务
将对象想象为服务提供者。如果我可以将问题从表象抽象出来,什么样的对象能够解决我的问题?
将对象想象为服务提供者的好处是:可以提供对象的内聚性。高内聚是软件设计的基本要求之一。
【高内聚、低耦合】
内聚:每个模块尽可能独立完成自己的功能,不依赖于模块外部的代码。
耦合:模块与模块之间接口的复杂程度,模块之间联系越复杂耦合度越高,牵一发而动全身。
目的:使得模块的“可重用性”、“移植性”大大增强
1.4 被隐藏的具体实现
程序人员分为:类创建者和客户端程序员。
控制访问:首先可以使得客户端程序员无法触及他们不需要接触的部分,其次,允许库设计者可以更改内部的工作方式而不用担心影响客户端程序员(接口和实现的分离)。
Java 用三个关键字在类的内部设定边界:public,private,protected。
1.5 复用的具体实现
组合:新的类可以由多个现有的类合成。
聚合:组合是动态发生的。
组合中新类的成员对象通常声明为private 使得客户端程序员不能访问。建立对象首先考虑组合而不是继承,继承会使得设计过分的复杂。
1.6 继承
基类用来表示类型之间的相似性,包含某些对象的核心概念,导出类表示此核心可以实现不同的方式。所有发给基类的消息同时也可以发给导出类。如果仅仅继承一个类不做任何其他的事情,就没有任何意义。两种方式产生差异(子类和父类):1 在导出类中添加新的方法。2 覆盖父类的方法。
如果只覆盖基类的方法,就意味着子类和父类是相同的类型,可以视为纯粹的替代。
有时给导出类中添加了新的接口元素,就扩展了接口。新的类型具有旧的类型的接口,同时还包含别的方法。是is-like-a 的关系。
1.7 伴随多态的可互换对象
添加新类型是扩展一个面向对象程序的常用方式。通过导出新的子类型而轻松扩展设计的能力是对改动进行封装的基本方式。
如何确定调用哪一个move?
非面向对象的编译器产生的函数调用会引起前期绑定,编译器将产生对一个具体函数名字的调用,运行时将调用解析到将要被执行的代码的绝对地址。
面向对象程序设计语言使用后期绑定,当向对象发送消息时,被调用代码知道运行时才确认,所以编译器确保被调用方法的存在,并对调用参数和返回值进行类型检查,但不知道被执行的确切代码。
为了执行后期绑定,Java 使用小段代码存储的信息来计算方法体的地址。每一个对象都可以具有不同的行为。
Java 动态绑定是默认行为,不需要额外的关键字来实现多态。
把导出类看做基类的过程称为 向上转型(upcasting),一个面向对象的程序肯定会在某处向上转型,因为这样是知道确切类型的关键。
正是多态才能使得事情总是被正确的处理。即使设计向上转型,对象也能够知道执行什么样的正确的行为。
1.8 单根的继承结构
所有的class 都继承Object。 好处是所有的对象都具有一个公共的接口。单根继承结构使得所有的对象都具有某些功能,参数传递也得到简化。同时方便垃圾回收器(相比C++而言的巨大改进)。
1.9 容器
List,Map,Set。
1.9.1 参数化类型
存入容器时,必须向上转型为object,所以会丢失其身份(原有类型)。又产生了向下转型,Oject是Circle 还是Shape呢? 向上转型是安全的。但是向下转型并不是。如果转型错误,就会产生异常。而且向下转型的检查需要额外的时间。
使用参数化类型就可以自动定制用于特定类型上的类。JAVA SE5 重大变化就是添加了参数化类型。成为范型。
ArrayList shapes= new ArrayList();
1.10 对象的创建和生命周期
怎么控制对象的生命周期?C++ 认为效率控制是重要的议题,对象的存储空间和声明周期可以在编写程序时确定,通过将对象置于堆栈或限域对象或静态存储区来实现。这种方式将存储空间分配和释放置于优先考虑的位置。
这种方式牺牲了灵活性。因为必须在编程的时候确定对象的数量,生命周期,类型。
堆:内存中动态的创建对象,存储是动态管理的,所以需要时间来划分存储空间。动态方式对有一个一般性的逻辑假设:对象趋于变得复杂。所以查找和释放存储空间的开销不会对对象的创建造成重大的冲击。
Java 完全采用了动态内存分配方式。每当想要创建对象时,就要用new关键字来构建此对象的动态实例。
如果是在堆上面创建对象,编译器对其生命周期就会一无所知,C++必须通过编程的方式来确定何时销毁对象。Java通过垃圾回收器来处理内存释放问题。
1.11 异常处理
异常是一种对象,从出错点抛出,并且被特定类型错误的异常处理器捕获。异常处理与正常路径是并行的,在错误发生时执行另一条路径。异常提供了一种从错误状态恢复的途径。
异常处理不是面向对象的特征
1.12 并发编程
主进程的挂起是通过硬件的中断来触发的。但是这样难度太大,所以将问题分为多个可以独立的部分。提高任务的响应能力。线程是一种为单一处理器分配执行时间的手段。
1.13 Java 与 internet
Java 解决了www上面的程序设计问题