第一章 对象导论
- 抽象过程
- 每个对象都有一个接口
- 每个对象都提供服务
- 被隐藏的具体实现
- 复用具体实现
- 继承(“是一个”与“像是一个”关系)
- 伴随多态的可互换对象
- 单继承结构
- 容器(参数化类型)
- 对象的创建和生命期
- 异常处理:处理错误
- 并发编程
- Java与Internet
- Web是什么
- 客户端编程
- 服务器端编程
- 总结
(Object-oriented Programming)OOP面向对象程序设计
抽象过程
问题的复杂性取决于抽象的类型和质量
类型:“所抽象的是什么?” eg.1.汇编语言是对底层机器的轻微抽象 2.命令式语言(FORTRAN、C)对汇编语言的抽象
将问题空间中的元素及其在解空间中的表示称为“对象”(思想)
这样程序可以通过添加新类型的对象使自身适用某个特定问题
面向对象程序设计五种基本特性
- 万物皆对象
- 程序是对象的集合,它们通过发送消息来告知彼此所要做的
- 通过创建包含现有对象的包的方式来创建新类型的对象
- 每个对象都拥有其类型
- 某一特定类型的所有对象都可以接收同样的消息
对象具有状态、行为、标识
状态:内部数据
行为:方法
标识:每一个对象在内存中都有一个唯一的地址
每个对象都有一个接口
亚里士多德是第一个深入研究类型(type)的科学家----基本关键字class来引入新的类型
1.在程序执行期间具有不同的状态而其它方面都相似的对象会被分组到对象的类中----class关键字的由来
2.创建抽象数据类型(类)是面向对象程序设计的基本概念之一
3.抽象数据类型的运行方式与内置(bulit-in)类型完全一致:程序员可以创建某一类型的变量(对象或实例),然后操作这些变量(发送消息或请求;对象通过消息就知道做什么)
4.类描述了具有相同特性(数据元素)和行为(功能)的对象集合,所以类实际上就是一个数据类型;一旦类被建立,就可以随心所欲地创建类的任意个对象
难点:问题空间的元素和解空间的对象之间创建一对一的映射
怎样才能获得有用的对象呢?
必须有某种方式产生对对象的请求,使对象完成任务。(每个对象都只能满足某些请求,这些请求由对象的接口[interface]所定义,决定接口的便是类型)
Light it = new Light();
it.on()
接口确定了对某一特定对象所能发出的请求
向某个对象“发送消息”(产生请求),这个对象便知道此消息的目的,然后执行对应的程序代码
每个对象都提供服务
当程序员试图开发或理解一个程序设计时,最好的方法之一就是对象想象为“服务提供者”。
程序本身将向用户提供服务,它将通过调用其它对象提供的服务来实现这一目的。目标:创建能够提供理想的服务来解决问题的一系列对象
被隐藏的具体实现
程序开发人员按照角色可以分为类创建者(创建新数据类型的程序员)和客户端程序员(应用在其应用中使用数据类型的类消费者)
类创建者的目标是构建类,这种类有部分隐藏(对客户端程序员不可见):为什么?
被隐藏的部分通常代表对象内部脆弱的部分,它们很容易被粗心的或者不知内情的客户端程序员所毁坏,将其隐藏起来可以减少程序bug。
访问控制的原因:1.让客户端程序员无法触及它们不应该触及的部分 2.允许库设计者可以改变类内部的工作方式而不用担心影响到客户端程序员
Java三个关键字在类的内部设定边界
public:紧随其后的元素对任何人都是可用的
private除类型创建者和类型的内部方法之外的任何人都不能访问的元素
protected继承的类可以访问protected成员,但是不能访问private成员
默认访问权限类可以访问在同一包(库构件)中的其它类的成员,但是在包之外,这些成员如同指定了private一样
复用具体实现
一个类被创建并被测试完,就代表一个有用的代码单元,就要复用这个对象设计
复用这个类的方式:1.直接使用该类的一个对象 2.将那个类的一个对象置于某个新的类中(“创建一个新的成员对象”)新的类可以由任意数量、任意类型的其它对象以任意可以实现新的类中想要的功能的方式做组成。
组合(aggregation):使用现有的类合成新的类
组合极大灵活性:新类的成员对象通常都被声明为private,使用新类的客户端程序员不可以访问它们
继承
以现有类为基础,复制它,然后通过添加和修改这个副本来创建新类。
源类:基类、超类或父类
副本:导出类、继承类或子类
当继承现有类型时,就创造了新的类型。这个新的类型不仅包括现有类型的所有成员(尽管private成员被隐藏了起来,不可以访问),而且它复制了基类的接口
两种方法可以使基类与导出类产生差异
1.直接在导出类中添加新方法,这些新方法并不是基类接口的一部分
2.改变现有基类的方法(覆盖overriding)
直接在导出类中创建该方法的新定义。(我正在使用相同的接口方法,但是我想在新类型中做些不同的事情)
(“是一个”与“像是一个”关系)
- is-a(是一个):导出类对象完全替代一个基类对象----纯粹替代
- is-like-a(像是一个):添加了新的接口元素,基类不可以访问新添加的方法
伴随多态的可互换对象
处理类型的层次结构时,程序员都比较想把一个对象不当作它所属的特定类型来对待,而是将其作为基类的对象来对待。
操作:泛化其基类的特殊特征,使其不关心是否它们是特殊的类特征,都可以有自己的方法,这些方法都可以接收消息,程序员不用担心对象如何处理消息
BirdController对象泛化Bird对象,当move( )方法被调用时,即便忽略Bird的具体类型,也会产生(Goose走,Penguin游泳)
编译器工作原理:采用后期绑定【当对象发送消息时,被调用的代码直到运行时才能确定,编译器确保被调用方法的存在,并对调用参数和返回值执行类型检查】为了执行后期绑定,Java使用了一段特殊的代码来替代绝对地址调用。
void doSomething(shape shape) {
shape.erase();
//...
shape.draw();
这个方法可以与任何Shape对话,因为它是独立于任何它要绘制和擦除的对象的具体类型的。如果程序中其它部分用到了doSomething( )方法,doSomething( )的调用会自动地正确处理,而不管对象的确切类型
Circle circle = new Circle();
Triangle triangle = new Triangle();
Line line = new Line();
doSomthing(circle);
dosomthing(triangle);
dosomthing(line);
当一个对象发送消息时,即使涉及向上转型,该对象也知道要执行什么样的正确行为
将导出类看作它的基类的过程称为向上转型
单根继承结构
单根继承结构保证所有对象都具备某些功能,所有对象都可以很容易地在堆上创建,而参数传递也得到了极大的简化;在垃圾回收器的实现也变得容易的多。
容器
对于这样一个问题:解决特定问题需要多少个对象,或者它们存活多久;如何才能知道需要多少空间来创建这些对象呢?
面向对象设计中采用创建另一种对象类型,这种新的对象类型持有对其它对象的引用,被称为容器(集合)的新对象,可以在任何需要时都可以扩充自己以容纳程序员置于其中的所有东西
Java中提供了List(用于存储序列),Map(关联数组,用来建立对象之间的关联),Set(每种对象类型只持有一个),以及队列,树,堆栈
1.不同容器提供了不同类型的接口和外部行为
2.不同容器对于某些操作具有不同的效率
(参数化类型)
Java SE5后增加了参数化类型,称为范型,一对尖括号,中间包含类型信息,通过这些特征就可以识别对范型的使用
ArrayList<Shape> shapes = new ArrayList<Shape>();
参数化类型就是一个编译器可以自动定制作用于特定类型上的类。
对象的创建和声明周期
在使用对象时,最关键的问题之一便是它们的生成和销毁方式,每个对象为了生存都需要资源(内存)。程序员不需要一个对象时,就需要清除对象,使其占有的资源得以被释放和重用。
1.将对象置于堆栈(自动变量或限域变量或静态存储区域),将存储空间分配和释放置于优先考虑的位置。
2.在堆的内存池中动态地创建对象。这种方式中,直到运行时才知道需要多少对象,至于生命周期、具体类型在执行代码时才知道;因为存储空间是动态确定的,所以在分配空间时间大于创建空间时间。在堆栈上创建存储空间和释放存储空间通常需要一条汇编指令即可,分别对应栈顶指针向下移动和将栈顶指针向上移动。
Java采用动态内存分配方式,每次创建新对象时,就要使用new关键字来构建此对象的动态实例。Java采用垃圾回收机制,可以自动发现对象何时不使用,并继而销毁它。(基于单根基类和在堆上创建)
异常处理:处理错误
异常是一种对象,它从出错地点被“抛出”,并被专门设计用来处理特定类型错误的相应的异常处理器“捕获”
异常处理:与程序正常执行路径并行的、在错误发生时执行的另一条路径。
并发编程
程序员用掌握有关机器底层的知识来编写中断服务程序,主进程的挂起通过硬件中断来触发;虽然可以解决同一时刻处理多个任务,但是难度太大,在不同机器上程序也不能够移植
并发:问题切分成多个可独立运行的部分(任务),从而提高程序的响应能力,这些彼此独立运行的部分称之为线程
线程:单一处理器分配执行时间的手段
Java的并发是内置于语言中,Java SE5已经增添了大量额外的库支持
Java与Internet
Web是什么
1.客户/服务器计算技术
客户/服务器系统核心思想:系统具有一个中央信息存储池,用来存储某种数据,通常存在于数据库中,程序员根据需要将它分发给某些人员或机器集群。
服务器:信息存储池、用于分发信息的软件以及信息与软件所驻留的机器或机群
客户机:驻留在用户机器上的软件与服务器进行通信,以获取信息、处理信息
问题:只有一个单一的服务器却要同时为多个客户服务
1.保证每一个客户插入数据库的新数据不会覆盖另一个客户插入的新数据
2.不会将其添加到数据库的过程中丢失(事务处理)
3.支持多种不同的类型的计算机和操作系统更麻烦
4.寻求成千上万的客户向服务器的请求,力图将延迟最小化
2.Web就是一台巨型服务器
你对某个服务器产生一个请求,然后它返回给你一个文件,你的机器(客户机)上的浏览器软件根据本地机器的格式来解读这个文件。
技术发展,人们不仅仅希望服务器传递回页面,更希望客户可以将信息反馈给服务器
为了解决这个问题,程序员采用了在浏览器中增加了可运行程序的能力“客户端编程”
客户端编程
客户端编程:与传统意义上的编程不同,参数几乎相同,平台不同,Web浏览器就像一个功能受限的操作系统,有三方面对客户端编程处理方法进行论述
1.插件(plug-in)
程序员可以通过这种方式下载一段代码,插入浏览器中适当位置,以此来为浏览器添加新的功能。
价值:允许专家级的程序员不需要经过浏览器生产商的许可,就可以开发某种语言的扩展,并将它们增添到服务器中
2.脚本语言
浏览器脚本语言,可以将客户端程序的源代码直接嵌入到HTML页面中,解释这种语言的插件在HTML页面被显示时自动激活。
如果你期望有一种脚本语言在Web浏览器不需要任何插件的情况下就可以得到支持,那它就是JavaScript,脚本语言可以解决客户端编程中遇到的百分之八十的问题
3.Java
Java通过applet以及使用Java Web Start来进行客户端编程
服务器端编程
Java用到servlet以及其衍生物JSP开发
总结
面向对象程序设计:1.用来表示问题空间概念的对象 2.发送给这些对象的用来表示在此空间的行为的消息 3.阅读它就可以很容易地理解其代码