【正文】
決辦法似乎都有些輕率——只是簡(jiǎn)單地創(chuàng)建另一種類型的對(duì)象。幸運(yùn)的是,設(shè)計(jì)優(yōu)良的OOP語(yǔ)言都配套提供了一系列集合。其中包括集、隊(duì)列、散列表、樹、堆棧等等。如果想對(duì)集合中的一系列元素進(jìn)行操縱或比較,而不是僅僅面向一個(gè),這時(shí)又該怎么辦呢?辦法就是使用一個(gè)“繼續(xù)器”(Iterator),它屬于一種對(duì)象,負(fù)責(zé)選擇集合內(nèi)的元素,并把它們提供給繼承器的用戶。從設(shè)計(jì)角度出發(fā),我們需要的是一個(gè)全功能的序列。最好的例子便是矢量(Vector)和列表(List)的區(qū)別。在設(shè)計(jì)階段,我們可以先從一個(gè)列表開始。2 單根結(jié)構(gòu)在面向?qū)ο蟮某绦蛟O(shè)計(jì)中,由于C++的引入而顯得尤為突出的一個(gè)問題是:所有類最終是否都應(yīng)從單獨(dú)一個(gè)基礎(chǔ)類繼承。理所當(dāng)然地,這也需要付出額外的精力使新接口與自己的設(shè)計(jì)方案配合(可能還需要多重繼承)。如果沒有這種單根結(jié)構(gòu),而且系統(tǒng)通過(guò)一個(gè)句柄來(lái)操縱對(duì)象,那么實(shí)現(xiàn)垃圾收集器的途徑會(huì)有很大的不同,而且會(huì)面臨許多障礙。這使我們對(duì)它的重復(fù)使用變得非常簡(jiǎn)便。舉個(gè)例子來(lái)說(shuō),我們知道在上溯造型的時(shí)候,Circle(圓)屬于Shape(幾何形狀)的一種類型,所以上溯造型是安全的。例如,通過(guò)使用一個(gè)參數(shù)化集合,編譯器可對(duì)那個(gè)集合進(jìn)行定制,使其只接受Shape,而且只提取Shape。既然如此,我們能不能創(chuàng)建一個(gè)“智能”集合,令其知道自己容納的類型呢?這樣做可消除下溯造型的必要以及潛在的錯(cuò)誤。而是下溯造型成一種更“特殊”的類型。下溯造型與模板/通用性為了使這些集合能夠重復(fù)使用,或者“再生”,Java提供了一種通用類型,以前曾把它叫作“Object”。利用單根結(jié)構(gòu),我們可以更方便地實(shí)現(xiàn)一個(gè)垃圾收集器。但假期我們想進(jìn)行純粹的面向?qū)ο缶幊蹋敲幢仨殬?gòu)建自己的結(jié)構(gòu),以期獲得與內(nèi)建到其他OOP語(yǔ)言里的同樣的便利。我們可能只需要一種類型的序列。但在另一方面,如果想在序列中部插入一個(gè)元素,用列表就比用矢量劃算得多。利用這個(gè)特征,我們解決問題時(shí)便有更大的靈活性。Java最開始()提供的是一個(gè)標(biāo)準(zhǔn)繼承器,名為Enumeration(枚舉),為它的所有集合類提供服務(wù)。但在許多情況下,這樣做往往會(huì)無(wú)功而返。例如,可以用一個(gè)矢量統(tǒng)一對(duì)所有元素的訪問方式;一個(gè)鏈接列表則用于保證所有元素的插入統(tǒng)一。所以我們事先不必知道要在一個(gè)集合里容下多少東西。1 集合與繼承器針對(duì)一個(gè)特定問題的解決,如果事先不知道需要多少個(gè)對(duì)象,或者它們的持續(xù)時(shí)間有多長(zhǎng),那么也不知道如何保存那些對(duì)象。大家或許認(rèn)為既然它如此靈活,那么無(wú)論如何都應(yīng)在內(nèi)存堆里創(chuàng)建對(duì)象,而不是在堆棧中創(chuàng)建。第二個(gè)方法是在一個(gè)內(nèi)存池中動(dòng)態(tài)創(chuàng)建對(duì)象,該內(nèi)存池亦叫“堆”或者“內(nèi)存堆”。最重要的問題之一是對(duì)象的創(chuàng)建及破壞方式。外文資料Object landscapes and lifetimesTechnically, OOP is just about abstract data typing, inheritance, and polymorphism, but other issues can be at least as important. The remainder of this section will cover these issues. One of the most important factors is the way objects are created and destroyed. Where is the data for an object and how is the lifetime of the object controlled? There are different philosophies at work here. C++ takes the approach that control of efficiency is the most important issue, so it gives the programmer a choice. For maximum runtime speed, the storage and lifetime can be determined while the program is being written, by placing the objects on the stack (these are sometimes called automatic or scoped variables) or in the static storage area. This places a priority on the speed of storage allocation and release, and control of these can be very valuable in some situations. However, you sacrifice flexibility because you must know the exact quantity, lifetime, and type of objects while you39。本節(jié)將就這些問題進(jìn)行探討。如果要解決的是一個(gè)較常規(guī)的問題,如計(jì)算機(jī)輔助設(shè)計(jì)、倉(cāng)儲(chǔ)管理或者空中交通控制,這一方法就顯得太局限了。C++允許我們決定是在寫程序時(shí)創(chuàng)建對(duì)象,還是在運(yùn)行期間創(chuàng)建,這種控制方法更加靈活。本節(jié)剩下的部分將討論操縱對(duì)象時(shí)要考慮的另一些因素。在需要的時(shí)候,集合會(huì)自動(dòng)擴(kuò)充自己,以便適應(yīng)我們?cè)谄渲兄萌氲娜魏螙|西。在某些庫(kù)中,一個(gè)常規(guī)集合便可滿足人們的大多數(shù)要求;而在另一些庫(kù)中(特別是C++的庫(kù)),則面向不同的需求提供了不同類型的集合。如果是一個(gè)數(shù)組形式的實(shí)體,比如一個(gè)矢量(Vector),那么也許能用索引運(yùn)算符或函數(shù)。這樣一來(lái),我們就可以靈活地改變基礎(chǔ)數(shù)據(jù),不會(huì)對(duì)程序里的代碼造成干擾。堆棧的接口與行為與隊(duì)列的不同,而隊(duì)列的接口與行為又與一個(gè)集(Set)或列表的不同。而且假設(shè)某個(gè)元素位于列表較遠(yuǎn)的地方,找到它所需的時(shí)間也會(huì)長(zhǎng)許多。如果在一個(gè)編程環(huán)境中工作,它由于其他因素(比如在Windows下運(yùn)行,或者由垃圾收集器帶來(lái)了開銷)產(chǎn)生了內(nèi)在的開銷,那么矢量和鏈接列表之間在系統(tǒng)開銷上的差異就或許不是一個(gè)大問題。從向后兼容的角度看,這一方案可與C模型更好地配合,而且可以認(rèn)為它的限制更少一些。一個(gè)單根結(jié)構(gòu),加上所有對(duì)象都在內(nèi)存堆中創(chuàng)建,可以極大簡(jiǎn)化參數(shù)的傳遞(這在C++里是一個(gè)復(fù)雜的概念)。Java提供了這樣的一個(gè)庫(kù),盡管它在Java (Java )。但這一次不是在分級(jí)結(jié)構(gòu)中上溯造型成一種更“通用”的類型。下溯造型和運(yùn)行期檢查都要求花額外的時(shí)間來(lái)運(yùn)行程序,而且程序員必須付出額外的精力。Java采取的這種關(guān)鍵字保留機(jī)制其實(shí)經(jīng)常讓人摸不著頭腦,很難斷定以后會(huì)發(fā)生什么事情。參數(shù)化類型是C++一個(gè)重要的組成部分,這部分是C++沒有單根結(jié)構(gòu)的緣故。但我們不知道一個(gè)Object到底是Circle還是Shape,所以很難保證下溯造型的安全進(jìn)行,除非確切地知道自己要操作的是什么。為使用這樣的一個(gè)集合,只需添加指向它的對(duì)象句柄即可,以后可以通過(guò)句柄重新使用對(duì)象。由于運(yùn)行期的類型信息肯定存在于所有對(duì)象中,所以永遠(yuǎn)不會(huì)遇到判斷不出一個(gè)對(duì)象的類型的情況。為得到C++額外的“靈活性”,付出這樣的代價(jià)值得嗎?當(dāng)然,如果真的需要——如果早已是C專家,如果對(duì)C有難舍的情結(jié)——那么就真的很值得。在Java中(與其他幾乎所有OOP語(yǔ)言一樣),對(duì)這個(gè)問題的答案都是肯定的,而且這個(gè)終級(jí)基礎(chǔ)類的名字很簡(jiǎn)單,就是一個(gè)“Object”。最后調(diào)整性能的時(shí)候,再根據(jù)情況把它換成矢量。它們都屬于簡(jiǎn)單的序列,擁有完全一致的接口和外部行為。通過(guò)對(duì)它的操縱,應(yīng)該能解決自己的問題。作為一個(gè)類,它也提供了一級(jí)抽象。所有集合都提供了相應(yīng)的讀寫功能。在C++中,它們是以“標(biāo)準(zhǔn)模板庫(kù)”(STL)的形式提供的。用于解決特定問題的新型對(duì)象容納了指向其他對(duì)象的句柄。程序員可用兩種方法來(lái)破壞一個(gè)對(duì)象:用程序化的方式?jīng)Q定何時(shí)破壞對(duì)象,或者利用由運(yùn)行環(huán)境提供的一種“垃圾收集器”特性,自動(dòng)尋找那些不再使用的對(duì)象,并將其清除。若需一個(gè)新對(duì)象,只需在需要它的時(shí)候在內(nèi)存堆里簡(jiǎn)單地創(chuàng)建它即可。為獲得最快的運(yùn)行速度,存儲(chǔ)以及存在時(shí)間可在編寫程序時(shí)決定,只需將對(duì)象放置在堆棧(有時(shí)也叫作自動(dòng)或定域變量)或者靜態(tài)存儲(chǔ)區(qū)域即可。s another issue, however, and that39。s the lifetime of an object. With languages that allow objects to be created on the stack, the piler determines how long the object lasts and can automatically destroy it. However, if you create it on the heap the piler has no knowledge of its lifetime. In a language like C++, you must determine p