友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
狗狗书籍 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第30章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




即对象的“存在时间”或者“生存时间”(Lifetime )。若在堆栈或者静态存储空间里创建一个对象,编译 

器会判断对象的持续时间有多长,到时会自动“破坏”或者“清除”它。程序员可用两种方法来破坏一个对 

象:用程序化的方式决定何时破坏对象,或者利用由运行环境提供的一种“垃圾收集器”特性,自动寻找那 

些不再使用的对象,并将其清除。当然,垃圾收集器显得方便得多,但要求所有应用程序都必须容忍垃圾收 

集器的存在,并能默许随垃圾收集带来的额外开销。但这并不符合C++语言的设计宗旨,所以未能包括到 C++ 

里。但Java 确实提供了一个垃圾收集器(Smalltalk 也有这样的设计;尽管 Delphi 默认为没有垃圾收集 

器,但可选择安装;而 C++亦可使用一些由其他公司开发的垃圾收集产品)。  

本节剩下的部分将讨论操纵对象时要考虑的另一些因素。  



1。7。1  集合与继承器  



针对一个特定问题的解决,如果事先不知道需要多少个对象,或者它们的持续时间有多长,那么也不知道如 

何保存那些对象。既然如此,怎样才能知道那些对象要求多少空间呢?事先上根本无法提前知道,除非进入 

运行期。  

在面向对象的设计中,大多数问题的解决办法似乎都有些轻率——只是简单地创建另一种类型的对象。用于 

解决特定问题的新型对象容纳了指向其他对象的句柄。当然,也可以用数组来做同样的事情,那是大多数语 

言都具有的一种功能。但不能只看到这一点。这种新对象通常叫作“集合”(亦叫作一个“容器”,但AWT 

在不同的场合应用了这个术语,所以本书将一直沿用“集合”的称呼。在需要的时候,集合会自动扩充自 

己,以便适应我们在其中置入的任何东西。所以我们事先不必知道要在一个集合里容下多少东西。只需创建 

一个集合,以后的工作让它自己负责好了。  

幸运的是,设计优良的 OOP 语言都配套提供了一系列集合。在 C++中,它们是以“标准模板库”(STL)的形 

式提供的。Object Pascal 用自己的“可视组件库”(VCL)提供集合。Smalltalk 提供了一套非常完整的集 

合。而 Java 也用自己的标准库提供了集合。在某些库中,一个常规集合便可满足人们的大多数要求;而在另 



                                                           33 


…………………………………………………………Page 35……………………………………………………………

一些库中(特别是 C++的库),则面向不同的需求提供了不同类型的集合。例如,可以用一个矢量统一对所 

有元素的访问方式;一个链接列表则用于保证所有元素的插入统一。所以我们能根据自己的需要选择适当的 

类型。其中包括集、队列、散列表、树、堆栈等等。  

所有集合都提供了相应的读写功能。将某样东西置入集合时,采用的方式是十分明显的。有一个叫作“推” 

 (Push )、“添加”(Add)或其他类似名字的函数用于做这件事情。但将数据从集合中取出的时候,方式却 

并不总是那么明显。如果是一个数组形式的实体,比如一个矢量(Vector),那么也许能用索引运算符或函 

数。但在许多情况下,这样做往往会无功而返。此外,单选定函数的功能是非常有限的。如果想对集合中的 

一系列元素进行操纵或比较,而不是仅仅面向一个,这时又该怎么办呢?  

办法就是使用一个“继续器”(Iterator),它属于一种对象,负责选择集合内的元素,并把它们提供给继 

承器的用户。作为一个类,它也提供了一级抽象。利用这一级抽象,可将集合细节与用于访问那个集合的代 

码隔离开。通过继承器的作用,集合被抽象成一个简单的序列。继承器允许我们遍历那个序列,同时毋需关 

心基础结构是什么——换言之,不管它是一个矢量、一个链接列表、一个堆栈,还是其他什么东西。这样一 

来,我们就可以灵活地改变基础数据,不会对程序里的代码造成干扰。Java 最开始(在 1。0和 1。1版中)提 

供的是一个标准继承器,名为 Enumeration (枚举),为它的所有集合类提供服务。Java 1。2 新增一个更复 

杂的集合库,其中包含了一个名为 Iterator 的继承器,可以做比老式的Enumeration 更多的事情。  

从设计角度出发,我们需要的是一个全功能的序列。通过对它的操纵,应该能解决自己的问题。如果一种类 

型的序列即可满足我们的所有要求,那么完全没有必要再换用不同的类型。有两方面的原因促使我们需要对 

集合作出选择。首先,集合提供了不同的接口类型以及外部行为。堆栈的接口与行为与队列的不同,而队列 

的接口与行为又与一个集(Set)或列表的不同。利用这个特征,我们解决问题时便有更大的灵活性。  

其次,不同的集合在进行特定操作时往往有不同的效率。最好的例子便是矢量(Vector)和列表(List )的 

区别。它们都属于简单的序列,拥有完全一致的接口和外部行为。但在执行一些特定的任务时,需要的开销 

却是完全不同的。对矢量内的元素进行的随机访问(存取)是一种常时操作;无论我们选择的选择是什么, 

需要的时间量都是相同的。但在一个链接列表中,若想到处移动,并随机挑选一个元素,就需付出“惨重” 

的代价。而且假设某个元素位于列表较远的地方,找到它所需的时间也会长许多。但在另一方面,如果想在 

序列中部插入一个元素,用列表就比用矢量划算得多。这些以及其他操作都有不同的执行效率,具体取决于 

序列的基础结构是什么。在设计阶段,我们可以先从一个列表开始。最后调整性能的时候,再根据情况把它 

换成矢量。由于抽象是通过继承器进行的,所以能在两者方便地切换,对代码的影响则显得微不足道。  

最后,记住集合只是一个用来放置对象的储藏所。如果那个储藏所能满足我们的所有需要,就完全没必要关 

心它具体是如何实现的(这是大多数类型对象的一个基本概念)。如果在一个编程环境中工作,它由于其他 

因素(比如在Windows 下运行,或者由垃圾收集器带来了开销)产生了内在的开销,那么矢量和链接列表之 

间在系统开销上的差异就或许不是一个大问题。我们可能只需要一种类型的序列。甚至可以想象有一个“完 

美”的集合抽象,它能根据自己的使用方式自动改变基层的实现方式。  



1。7。2 单根结构  



在面向对象的程序设计中,由于C++的引入而显得尤为突出的一个问题是:所有类最终是否都应从单独一个 

基础类继承。在Java 中(与其他几乎所有OOP 语言一样),对这个问题的答案都是肯定的,而且这个终级基 

础类的名字很简单,就是一个“Object”。这种“单根结构”具有许多方面的优点。  

单根结构中的所有对象都有一个通用接口,所以它们最终都属于相同的类型。另一种方案(就象 C++那样) 

是我们不能保证所有东西都属于相同的基本类型。从向后兼容的角度看,这一方案可与C 模型更好地配合, 

而且可以认为它的限制更少一些。但假期我们想进行纯粹的面向对象编程,那么必须构建自己的结构,以期 

获得与内建到其他 OOP 语言里的同样的便利。需添加我们要用到的各种新类库,还要使用另一些不兼容的接 

口。理所当然地,这也需要付出额外的精力使新接口与自己的设计方案配合(可能还需要多重继承)。为得 

到C++额外的“灵活性”,付出这样的代价值得吗?当然,如果真的需要——如果早已是 C 专家,如果对C 

有难舍的情结——那么就真的很值得。但假如你是一名新手,首次接触这类设计,象Java 那样的替换方案也 

许会更省事一些。  

单根结构中的所有对象(比如所有 Java 对象)都可以保证拥有一些特定的功能。在自己的系统中,我们知道 

对每个对象都能进行一些基本操作。一个单根结构,加上所有对象都在内存堆中创建,可以极大简化参数的 

传递(这在 C++里是一个复杂的
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!