友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第15部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


 “从不同的角度观察世界”—— “所有问题都归纳为列表”或“所有问题都归纳为算法”。PROLOG 则将所有 

问题都归纳为决策链。对于这些语言,我们认为它们一部分是面向基于“强制”的编程,另一部分则是专为 

处理图形符号设计的。每种方法都有自己特殊的用途,适合解决某一类的问题。但只要超出了它们力所能及 

的范围,就会显得非常笨拙。  

面向对象的程序设计在此基础上则跨出了一大步,程序员可利用一些工具表达问题空间内的元素。由于这种 

表达非常普遍,所以不必受限于特定类型的问题。我们将问题空间中的元素以及它们在方案空间的表示物称 

作“对象”(Object)。当然,还有一些在问题空间没有对应体的其他对象。通过添加新的对象类型,程序 

可进行灵活的调整,以便与特定的问题配合。所以在阅读方案的描述代码时,会读到对问题进行表达的话 

语。与我们以前见过的相比,这无疑是一种更加灵活、更加强大的语言抽象方法。总之,OOP 允许我们根据 

问题来描述问题,而不是根据方案。然而,仍有一个联系途径回到计算机。每个对象都类似一台小计算机; 

它们有自己的状态,而且可要求它们进行特定的操作。与现实世界的“对象”或者“物体”相比,编程“对 

象”与它们也存在共通的地方:它们都有自己的特征和行为。  

Alan Kay 总结了 Smalltalk 的五大基本特征。这是第一种成功的面向对象程序设计语言,也是Java 的基础 

语言。通过这些特征,我们可理解“纯粹”的面向对象程序设计方法是什么样的:  

(1) 所有东西都是对象。可将对象想象成一种新型变量;它保存着数据,但可要求它对自身进行操作。理论 

上讲,可从要解决的问题身上提出所有概念性的组件,然后在程序中将其表达为一个对象。  

(2) 程序是一大堆对象的组合;通过消息传递,各对象知道自己该做些什么。为了向对象发出请求,需向那 



                                                               27 


…………………………………………………………Page 29……………………………………………………………

个对象“发送一条消息”。更具体地讲,可将消息想象为一个调用请求,它调用的是从属于目标对象的一个 

子例程或函数。  

(3) 每个对象都有自己的存储空间,可容纳其他对象。或者说,通过封装现有对象,可制作出新型对象。所 

以,尽管对象的概念非常简单,但在程序中却可达到任意高的复杂程度。  

(4) 每个对象都有一种类型。根据语法,每个对象都是某个“类”的一个“实例”。其中,“类”(Class) 

是“类型”(Type )的同义词。一个类最重要的特征就是“能将什么消息发给它?”。  

(5) 同一类所有对象都能接收相同的消息。这实际是别有含义的一种说法,大家不久便能理解。由于类型为 

 “圆”(Circle)的一个对象也属于类型为“形状”(Shape)的一个对象,所以一个圆完全能接收形状消 

息。这意味着可让程序代码统一指挥“形状”,令其自动控制所有符合“形状”描述的对象,其中自然包括 

 “圆”。这一特性称为对象的“可替换性”,是OOP 最重要的概念之一。  

  

一些语言设计者认为面向对象的程序设计本身并不足以方便解决所有形式的程序问题,提倡将不同的方法组 

合成“多形程序设计语言”(注释②)。  

  

②:参见Timothy Budd 编著的《Multiparadigm Programming in Leda》,Addison…Wesley 1995 年出版。  



1。2 对象的接口  



亚里士多德或许是认真研究“类型”概念的第一人,他曾谈及“鱼类和鸟类”的问题。在世界首例面向对象 

语言Simula…67 中,第一次用到了这样的一个概念:  

所有对象——尽管各有特色——都属于某一系列对象的一部分,这些对象具有通用的特征和行为。在 

Simula…67 中,首次用到了class 这个关键字,它为程序引入了一个全新的类型(clas 和 type 通常可互换使 

用;注释③)。  

  

③:有些人进行了进一步的区分,他们强调“类型”决定了接口,而“类”是那个接口的一种特殊实现方 

式。  

  

Simula 是一个很好的例子。正如这个名字所暗示的,它的作用是“模拟”(Simulate )象“银行出纳员”这 

样的经典问题。在这个例子里,我们有一系列出纳员、客户、帐号以及交易等。每类成员(元素)都具有一 

些通用的特征:每个帐号都有一定的余额;每名出纳都能接收客户的存款;等等。与此同时,每个成员都有 

自己的状态;每个帐号都有不同的余额;每名出纳都有一个名字。所以在计算机程序中,能用独一无二的实 

体分别表示出纳员、客户、帐号以及交易。这个实体便是“对象”,而且每个对象都隶属一个特定的 

 “类”,那个类具有自己的通用特征与行为。  

因此,在面向对象的程序设计中,尽管我们真正要做的是新建各种各样的数据“类型”(Type ),但几乎所 

有面向对象的程序设计语言都采用了“class”关键字。当您看到“type”这个字的时候,请同时想到 

 “class”;反之亦然。  

建好一个类后,可根据情况生成许多对象。随后,可将那些对象作为要解决问题中存在的元素进行处理。事 

实上,当我们进行面向对象的程序设计时,面临的最大一项挑战性就是:如何在“问题空间”(问题实际存 

在的地方)的元素与“方案空间”(对实际问题进行建模的地方,如计算机)的元素之间建立理想的“一对 

一”对应或映射关系。  

如何利用对象完成真正有用的工作呢?必须有一种办法能向对象发出请求,令其做一些实际的事情,比如完 

成一次交易、在屏幕上画一些东西或者打开一个开关等等。每个对象仅能接受特定的请求。我们向对象发出 

的请求是通过它的“接口”(Interface)定义的,对象的“类型”或“类”则规定了它的接口形式。“类 

型”与“接口”的等价或对应关系是面向对象程序设计的基础。  

下面让我们以电灯泡为例:  

  



                                                                  28 


…………………………………………………………Page 30……………………………………………………………

                                    

Light lt = new Light();  

lt。on();  

  

在这个例子中,类型/类的名称是 Light,可向 Light 对象发出的请求包括包括打开(on)、关闭(off)、 

变得更明亮(brighten )或者变得更暗淡(dim)。通过简单地声明一个名字(lt),我们为Light 对象创建 

了一个“句柄”。然后用new 关键字新建类型为 Light 的一个对象。再用等号将其赋给句柄。为了向对象发 

送一条消息,我们列出句柄名(lt),再用一个句点符号(。)把它同消息名称(on)连接起来。从中可以看 

出,使用一些预先定义好的类时,我们在程序里采用的代码是非常简单和直观的。  



1。3 实现方案的隐藏  



为方便后面的讨论,让我们先对这一领域的从业人员作一下分类。从根本上说,大致有两方面的人员涉足面 

向对象的编程:“类创建者”(创建新数据类型的人)以及“客户程序员”(在自己的应用程序中采用现成 

数据类型的人;注释④)。对客户程序员来讲,最主要的目标就是收集一个充斥着各种类的编程“工具 

箱”,以便快速开发符合自己要求的应用。而对类创建者来说,他们的目标则是从头构建一个类,只向客户 

程序员开放有必要开放的东西(接口),其他所有细节都隐藏起来。为什么要这样做?隐藏之后,客户程序 

员就不能接触和改变那些细节,所以原创者不用担心自己的作品会受到非法修改,可确保它们不会对其他人 

造成影响。  

  

④:感谢我的朋友 Scott Meyers,是他帮我起了这个名字。  

  

 “接口”(Interface)规定了可对一个特定的对象发出哪些请求。然而,必须在某个地方存在着一些代码, 

以便满足这些请求。这些代码与那些隐藏起来的数据便叫作“隐藏的实现”。站在程式化程序编写 

 (Procedural Programming )的角度,整个问题并不显得复杂。一种类型含有与每种可能的请求关联起来的 

函数。一旦向对象发出一个特定的请求,就会调用那个函数。我们通常将这个过程总结为向对象“发送一条 

消息”(提出一个请求)。对象的职责就是决定如何对这条消息作出反应(执行相应的代码)。  

对于任何关系,重要一点是让牵连到的所有成员都遵守相同的规则。创建一个库时,相当于同客户程序员建 

立了一种关系。对方也是程序员,但他们的目标是组合出一个特定的应用(程序),或者用您的库构建一个 

更大的库。  

若任何人都能使用一个类的所有成员,那么客户程序员可对那个类做任何事情,没有办法强制他们遵守任何 

约束。即便非常不愿客户程序员直接操作类内包含的一些成员,但倘若未进行访问控制,就没有办法阻止这 

一情况的发生——所有东西都会暴露无遗。  

有两方面的原因促使我们控制对成员的访问。第一个原因是防止程序员接触他们不该接触的东西——通常是 

内部数据类型的设计思想。若只是为了解决特定的问题,用户只需操作接口即可,毋需明白这些信息。我们 

向用户提供的实际是一种服务,因为他们很容易就可看出哪些对自己非常重要,以及哪些可忽略不计。  

进行访问控制的第二个原因是允许库设计人员修改内部结构,不用担心它会对客户程序员造成什么影响。例 

如,我们最开始可能设计了一个形式简单的类,以便简化开发。以后又决定进行改写,使其更快地运行。若 

接口与实现方法早已隔离开,并分别受到保护,就可放心做到这一点,只要求用户重新链接一下即可。  

Java 采用三个显式(明确)关键字以及一个隐式(暗示)关键字来设置类边界:public,private, 

protected 以及暗示性的friendly。若未明确指定其他关键字,则默认为后者。这些关键字的使用和含义都 

是相当直观的,它们决定了谁能使用后续的定义内容。“public”(公共)意味着后续的定义任何人均可使 

用。而在另一方面,“private”(私有)意味着除您自己、类型的创建者以及那个类型的内部函数成员,其 

他任何人都不能访问后续的定义信息。private 在您与客户程序员之间竖起了一堵墙。若有人试图访问私有 



                                                                  29 


…………………………………………………………Page 31……………………………………………………………

成员,就会得到一个编译期错误。“friendly ”(友好的)涉及“包装”或“封装”(Package)的概念—— 

即Java 用来构建库的方法。若某样东西是“友好的”,意味着它只能在这个包装的范围内使用(所以这一访 

问级别有时也叫作“包装访问”)。“protected”(受保护的)与“private”相似,只是一个继承的类可 

访问受保护的成员,但不能访问私有成员。继承的问题不久就要谈到。  



1。4 方案的重复使用  



创建并测试好一个类后,它应(从理想的角度)代表一个有用的代码单位。但并不象许多人希望的那样,这 

种重复使用的能力并不容易实现;它要求较多的经验以及洞察力,这样才能设计出一个好的方案,才有可能 

重复使用。  

许多人认为代码或设计方案的重复使用是面向对象的程序设计提供的最伟大的一种杠杆。  

为重复使用一个类,最简单的办法是仅直接使用那个类的对象。但同时也能将那个类的一个对象置入一个新 

类。我们把这叫作“创建一个成员对象”。新类可由任意数量和类型的其他对象构成。无论如何,只要新类 

达到了设计要求即可。这个概念叫作“组织”——在现有类的基础上组织一个新类。有时,我们也将组织称 

作“包含”关系,比如“一辆车包含了一个变速箱”。  

对象的组织具有极大的灵活性。新类的“成员对象”通常设为“私有”(Private),使用这个类的客户程序 

员不能访问它们。这样一来,我们可在不干扰客户代码的前提下,从容地修改那些成员。也可以在“运行 

期”更改成员,这进一步增大了灵活性。后面要讲到的“继承”并不具备这种灵活性,因为编译器必须对通 

过继承创建的类加以限制。  

由于继承的重要性,所以在面向对象的程序设计中,它经常被重点强调。作为新加入这一领域的程序员,或 

许早已先入为主地认为“继承应当随处可见”。沿这种思路产生的设计将是非常笨拙的,会大大增加程序的 

复杂程度。相反,新建类的时候,首先应考虑“组织”对象;这样做显得更加简单和灵活。利用对象的组 

织,我们的设计可保持清爽。一旦需要用到继承,就会明显意识到这一点。  



1。5 继承:重新使用接口  



就其本身来说,对象的概念可为我们带来极大的便利。它在概念上允许我们将各式各样数据和功能封装到一 

起。这样便可恰当表达“问题空间”的概念,不用刻意遵照基础机器的表达方式。在程序设计语言中,这些 

概念则反映为具体的数据类型(使用class 关键字)。  

我们费尽心思做出一种数据类型后,假如不得不又新建一种类型,令其实现大致相同的功能,那会是一件非 

常令人灰心的事情。但若能利用现成的数据类型,对其进行“克隆”,再根据情况进行添加和修改,情况就 

显得理想多了。“继承”正是针对这个目标而设计的。但继承并不完全等价于克隆。在继承过程中,若原始 

类(正式名称叫作基础类、超类或父类)发生了变化,修改过的“克隆”类(正式名称叫作继承类或者子 

类)也会反映出这种变化。在 Java 语言中,继承是通过 extends 关键字实现的  

使用继承时,相当于创建了一个新类。这个新类不仅包含了现有类型的所有成员(尽管private 成员被隐藏 

起来,且不能访问),但更重要的是,它复制了基础类的接口。也就是说,可向基础类的对象发送的所有消 

息亦可原样发给衍生类的对象。根据可以发送的消息,我们能知道类的类型。这意味着衍生类具有与基础类 

相同的类型!为真正理解面向对象程序设计的含义,首先必须认识到这种类型的等价关系。  

由于基础类和衍生类具有相同的接口,所以那个接口必须进行特殊的设计。也就是说,对象接收到一条特定 

的消息后,必须有一个“方法”能够执行。若只是简单地继承一
返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!