2023年全國碩士研究生考試考研英語一試題真題(含答案詳解+作文范文)_第1頁
已閱讀1頁,還剩14頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、<p><b>  外文資料</b></p><p>  Object landscapes and lifetimes</p><p>  Technically, OOP is just about abstract data typing, inheritance, and polymorphism, but other issues can be a

2、t least as important. The remainder of this section will cover these issues. </p><p>  One of the most important factors is the way objects are created and destroyed. Where is the data for an object and how

3、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 run

4、-time 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 auto</p><p>  The second approach is to create obje

5、cts dynamically in a pool of memory called the heap. In this approach, you don't know until run-time how many objects you need, what their lifetime is, or what their exact type is. Those are determined at the spur of

6、 the moment while the program is running. If you need a new object, you simply make it on the heap at the point that you need it. Because the storage is managed dynamically, at run-time, the amount of time required to al

7、locate storage on the heap </p><p>  Java uses the second approach, exclusively]. Every time you want to create an object, you use the new keyword to build a dynamic instance of that object. </p><

8、p>  There's another issue, however, and that's the lifetime of an object. With languages that allow objects to be created on the stack, the compiler determines how long the object lasts and can automatically d

9、estroy it. However, if you create it on the heap the compiler has no knowledge of its lifetime. In a language like C++, you must determine programmatically when to destroy the object, which can lead to memory leaks if yo

10、u don’t do it correctly (and this is a common problem in C++ programs). Jav</p><p>  The rest of this section looks at additional factors concerning object lifetimes and landscapes. </p><p>  1

11、Collections and iterators</p><p>  If you don’t know how many objects you’re going to need to solve a particular problem, or how long they will last, you also don’t know how to store those objects. How can y

12、ou know how much space to create for those objects? You can’t, since that information isn’t known until run-time. </p><p>  The solution to most problems in object-oriented design seems flippant: you create

13、another type of object. The new type of object that solves this particular problem holds references to other objects. Of course, you can do the same thing with an array, which is available in most languages. But there’s

14、more. This new object, generally called a container (also called a collection, but the Java library uses that term in a different sense so this book will use “container”), will expand itself whenev</p><p>  

15、Fortunately, a good OOP language comes with a set of containers as part of the package. In C++, it’s part of the Standard C++ Library and is sometimes called the Standard Template Library (STL). Object Pascal has contain

16、ers in its Visual Component Library (VCL). Smalltalk has a very complete set of containers. Java also has containers in its standard library. In some libraries, a generic container is considered good enough for all needs

17、, and in others (Java, for example) the library has differen</p><p>  All containers have some way to put things in and get things out; there are usually functions to add elements to a container, and others

18、to fetch those elements back out. But fetching elements can be more problematic, because a single-selection function is restrictive. What if you want to manipulate or compare a set of elements in the container instead of

19、 just one? </p><p>  The solution is an iterator, which is an object whose job is to select the elements within a container and present them to the user of the iterator. As a class, it also provides a level

20、of abstraction. This abstraction can be used to separate the details of the container from the code that’s accessing that container. The container, via the iterator, is abstracted to be simply a sequence. The iterator al

21、lows you to traverse that sequence without worrying about the underlying structure—that is, wh</p><p>  From a design standpoint, all you really want is a sequence that can be manipulated to solve your probl

22、em. If a single type of sequence satisfied all of your needs, there’d be no reason to have different kinds. There are two reasons that you need a choice of containers. First, containers provide different types of interfa

23、ces and external behavior. A stack has a different interface and behavior than that of a queue, which is different from that of a set or a list. One of these might provide a mor</p><p>  In the end, remember

24、 that a container is only a storage cabinet to put objects in. If that cabinet solves all of your needs, it doesn’t really matter how it is implemented (a basic concept with most types of objects). If you’re working in a

25、 programming environment that has built-in overhead due to other factors, then the cost difference between an ArrayList and a LinkedList might not matter. You might need only one type of sequence. You can even imagine th

26、e “perfect” container abstraction, which</p><p>  2 The singly rooted hierarchy</p><p>  One of the issues in OOP that has become especially prominent since the introduction of C++ is whether al

27、l classes should ultimately be inherited from a single base class. In Java (as with virtually all other OOP languages) the answer is “yes” and the name of this ultimate base class is simply Object. It turns out that the

28、benefits of the singly rooted hierarchy are many. </p><p>  All objects in a singly rooted hierarchy have an interface in common, so they are all ultimately the same type. The alternative (provided by C++) i

29、s that you don’t know that everything is the same fundamental type. From a backward-compatibility standpoint this fits the model of C better and can be thought of as less restrictive, but when you want to do full-on obje

30、ct-oriented programming you must then build your own hierarchy to provide the same convenience that’s built into other OOP languages.</p><p>  All objects in a singly rooted hierarchy (such as Java provides)

31、 can be guaranteed to have certain functionality. You know you can perform certain basic operations on every object in your system. A singly rooted hierarchy, along with creating all objects on the heap, greatly simplifi

32、es argument passing (one of the more complex topics in C++). </p><p>  A singly rooted hierarchy makes it much easier to implement a garbage collector (which is conveniently built into Java). The necessary s

33、upport can be installed in the base class, and the garbage collector can thus send the appropriate messages to every object in the system. Without a singly rooted hierarchy and a system to manipulate an object via a refe

34、rence, it is difficult to implement a garbage collector. </p><p>  Since run-time type information is guaranteed to be in all objects, you’ll never end up with an object whose type you cannot determine. This

35、 is especially important with system level operations, such as exception handling, and to allow greater flexibility in programming. </p><p>  3 Collection libraries and support for easy collection use</p&

36、gt;<p>  Because a container is a tool that you’ll use frequently, it makes sense to have a library of containers that are built in a reusable fashion, so you can take one off the shelf Because a container is a to

37、ol that you’ll use frequently, it makes sense to have a library of containers that are built in a reusable fashion, so you can take one off the shelf and plug it into your program. Java provides such a library, which sho

38、uld satisfy most needs. </p><p>  Downcasting vs. templates/generics</p><p>  To make these containers reusable, they hold the one universal type in Java that was previously mentioned: Object. T

39、he singly rooted hierarchy means that everything is an Object, so a container that holds Objects can hold anything. This makes containers easy to reuse. </p><p>  To use such a container, you simply add obje

40、ct references to it, and later ask for them back. But, since the container holds only Objects, when you add your object reference into the container it is upcast to Object, thus losing its identity. When you fetch it bac

41、k, you get an Object reference, and not a reference to the type that you put in. So how do you turn it back into something that has the useful interface of the object that you put into the container? </p><p>

42、;  Here, the cast is used again, but this time you’re not casting up the inheritance hierarchy to a more general type, you cast down the hierarchy to a more specific type. This manner of casting is called downcasting. Wi

43、th upcasting, you know, for example, that a Circle is a type of Shape so it’s safe to upcast, but you don’t know that an Object is necessarily a Circle or a Shape so it’s hardly safe to downcast unless you know that’s wh

44、at you’re dealing with. </p><p>  It’s not completely dangerous, however, because if you downcast to the wrong thing you’ll get a run-time error called an exception, which will be described shortly. When you

45、 fetch object references from a container, though, you must have some way to remember exactly what they are so you can perform a proper downcast. </p><p>  Downcasting and the run-time checks require extra t

46、ime for the running program, and extra effort from the programmer. Wouldn’t it make sense to somehow create the container so that it knows the types that it holds, eliminating the need for the downcast and a possible mis

47、take? The solution is parameterized types, which are classes that the compiler can automatically customize to work with particular types. For example, with a parameterized container, the compiler could customize that con

48、tainer so</p><p>  Parameterized types are an important part of C++, partly because C++ has no singly rooted hierarchy. In C++, the keyword that implements parameterized types is “template.” Java currently h

49、as no parameterized types since it is possible for it to get by—however awkwardly—using the singly rooted hierarchy. However, a current proposal for parameterized types uses a syntax that is strikingly similar to C++ tem

50、plates. </p><p><b>  譯文</b></p><p>  對象的創(chuàng)建和存在時間</p><p>  從技術角度說,OOP(面向?qū)ο蟪绦蛟O計)只是涉及抽象的數(shù)據(jù)類型、繼承以及多形性,但另一些問題也可能顯得非常重要。本節(jié)將就這些問題進行探討。</p><p>  最重要的問題之一是對象的創(chuàng)建及破壞方式。

51、對象需要的數(shù)據(jù)位于哪兒,如何控制對象的“存在時間”呢?針對這個問題,解決的方案是各異其趣的。C++認為程序的執(zhí)行效率是最重要的一個問題,所以它允許程序員作出選擇。為獲得最快的運行速度,存儲以及存在時間可在編寫程序時決定,只需將對象放置在堆棧(有時也叫作自動或定域變量)或者靜態(tài)存儲區(qū)域即可。這樣便為存儲空間的分配和釋放提供了一個優(yōu)先級。某些情況下,這種優(yōu)先級的控制是非常有價值的。然而,我們同時也犧牲了靈活性,因為在編寫程序時,必須知道對象

52、的準確的數(shù)量、存在時間、以及類型。如果要解決的是一個較常規(guī)的問題,如計算機輔助設計、倉儲管理或者空中交通控制,這一方法就顯得太局限了。</p><p>  第二個方法是在一個內(nèi)存池中動態(tài)創(chuàng)建對象,該內(nèi)存池亦叫“堆”或者“內(nèi)存堆”。若采用這種方式,除非進入運行期,否則根本不知道到底需要多少個對象,也不知道它們的存在時間有多長,以及準確的類型是什么。這些參數(shù)都在程序正式運行時才決定的。若需一個新對象,只需在需要它的時

53、候在內(nèi)存堆里簡單地創(chuàng)建它即可。由于存儲空間的管理是運行期間動態(tài)進行的,所以在內(nèi)存堆里分配存儲空間的時間比在堆棧里創(chuàng)建的時間長得多(在堆棧里創(chuàng)建存儲空間一般只需要一個簡單的指令,將堆棧指針向下或向下移動即可)。由于動態(tài)創(chuàng)建方法使對象本來就傾向于復雜,所以查找存儲空間以及釋放它所需的額外開銷不會為對象的創(chuàng)建造成明顯的影響。除此以外,更大的靈活性對于常規(guī)編程問題的解決是至關重要的。</p><p>  C++允許我們決

54、定是在寫程序時創(chuàng)建對象,還是在運行期間創(chuàng)建,這種控制方法更加靈活。大家或許認為既然它如此靈活,那么無論如何都應在內(nèi)存堆里創(chuàng)建對象,而不是在堆棧中創(chuàng)建。</p><p>  但還要考慮另外一個問題,亦即對象的“存在時間”或者“生存時間”(Lifetime)。若在堆?;蛘哽o態(tài)存儲空間里創(chuàng)建一個對象,編譯器會判斷對象的持續(xù)時間有多長,到時會自動“破壞”或者“清除”它。程序員可用兩種方法來破壞一個對象:用程序化的方式?jīng)Q定

55、何時破壞對象,或者利用由運行環(huán)境提供的一種“垃圾收集器”特性,自動尋找那些不再使用的對象,并將其清除。當然,垃圾收集器顯得方便得多,但要求所有應用程序都必須容忍垃圾收集器的存在,并能默許隨垃圾收集帶來的額外開銷。但這并不符合C++語言的設計宗旨,所以未能包括到C++里。但Java確實提供了一個垃圾收集器(Smalltalk也有這樣的設計;盡管Delphi默認為沒有垃圾收集器,但可選擇安裝;而C++亦可使用一些由其他公司開發(fā)的垃圾收集產(chǎn)品

56、)。</p><p>  本節(jié)剩下的部分將討論操縱對象時要考慮的另一些因素。</p><p><b>  1 集合與繼承器</b></p><p>  針對一個特定問題的解決,如果事先不知道需要多少個對象,或者它們的持續(xù)時間有多長,那么也不知道如何保存那些對象。既然如此,怎樣才能知道那些對象要求多少空間呢?事先上根本無法提前知道,除非進入運行期

57、。</p><p>  在面向?qū)ο蟮脑O計中,大多數(shù)問題的解決辦法似乎都有些輕率——只是簡單地創(chuàng)建另一種類型的對象。用于解決特定問題的新型對象容納了指向其他對象的句柄。當然,也可以用數(shù)組來做同樣的事情,那是大多數(shù)語言都具有的一種功能。但不能只看到這一點。這種新對象通常叫作“集合”(亦叫作一個“容器”,但AWT在不同的場合應用了這個術語,所以本書將一直沿用“集合”的稱呼。在需要的時候,集合會自動擴充自己,以便適應我們

58、在其中置入的任何東西。所以我們事先不必知道要在一個集合里容下多少東西。只需創(chuàng)建一個集合,以后的工作讓它自己負責好了。</p><p>  幸運的是,設計優(yōu)良的OOP語言都配套提供了一系列集合。在C++中,它們是以“標準模板庫”(STL)的形式提供的。Object Pascal用自己的“可視組件庫”(VCL)提供集合。Smalltalk提供了一套非常完整的集合。而Java也用自己的標準庫提供了集合。在某些庫中,一個

59、常規(guī)集合便可滿足人們的大多數(shù)要求;而在另一些庫中(特別是C++的庫),則面向不同的需求提供了不同類型的集合。例如,可以用一個矢量統(tǒng)一對所有元素的訪問方式;一個鏈接列表則用于保證所有元素的插入統(tǒng)一。所以我們能根據(jù)自己的需要選擇適當?shù)念愋汀F渲邪?、隊列、散列表、樹、堆棧等等?lt;/p><p>  所有集合都提供了相應的讀寫功能。將某樣東西置入集合時,采用的方式是十分明顯的。有一個叫作“推”(Push)、“添加”(

60、Add)或其他類似名字的函數(shù)用于做這件事情。但將數(shù)據(jù)從集合中取出的時候,方式卻并不總是那么明顯。如果是一個數(shù)組形式的實體,比如一個矢量(Vector),那么也許能用索引運算符或函數(shù)。但在許多情況下,這樣做往往會無功而返。此外,單選定函數(shù)的功能是非常有限的。如果想對集合中的一系列元素進行操縱或比較,而不是僅僅面向一個,這時又該怎么辦呢?</p><p>  辦法就是使用一個“繼續(xù)器”(Iterator),它屬于一種

61、對象,負責選擇集合內(nèi)的元素,并把它們提供給繼承器的用戶。作為一個類,它也提供了一級抽象。利用這一級抽象,可將集合細節(jié)與用于訪問那個集合的代碼隔離開。通過繼承器的作用,集合被抽象成一個簡單的序列。繼承器允許我們遍歷那個序列,同時毋需關心基礎結構是什么——換言之,不管它是一個矢量、一個鏈接列表、一個堆棧,還是其他什么東西。這樣一來,我們就可以靈活地改變基礎數(shù)據(jù),不會對程序里的代碼造成干擾。Java最開始(在1.0和1.1版中)提供的是一個標

62、準繼承器,名為Enumeration(枚舉),為它的所有集合類提供服務。Java 1.2新增一個更復雜的集合庫,其中包含了一個名為Iterator的繼承器,可以做比老式的Enumeration更多的事情。</p><p>  從設計角度出發(fā),我們需要的是一個全功能的序列。通過對它的操縱,應該能解決自己的問題。如果一種類型的序列即可滿足我們的所有要求,那么完全沒有必要再換用不同的類型。有兩方面的原因促使我們需要對集

63、合作出選擇。首先,集合提供了不同的接口類型以及外部行為。堆棧的接口與行為與隊列的不同,而隊列的接口與行為又與一個集(Set)或列表的不同。利用這個特征,我們解決問題時便有更大的靈活性。</p><p>  其次,不同的集合在進行特定操作時往往有不同的效率。最好的例子便是矢量(Vector)和列表(List)的區(qū)別。它們都屬于簡單的序列,擁有完全一致的接口和外部行為。但在執(zhí)行一些特定的任務時,需要的開銷卻是完全不同

64、的。對矢量內(nèi)的元素進行的隨機訪問(存?。┦且环N常時操作;無論我們選擇的選擇是什么,需要的時間量都是相同的。但在一個鏈接列表中,若想到處移動,并隨機挑選一個元素,就需付出“慘重”的代價。而且假設某個元素位于列表較遠的地方,找到它所需的時間也會長許多。但在另一方面,如果想在序列中部插入一個元素,用列表就比用矢量劃算得多。這些以及其他操作都有不同的執(zhí)行效率,具體取決于序列的基礎結構是什么。在設計階段,我們可以先從一個列表開始。最后調(diào)整性能的時

65、候,再根據(jù)情況把它換成矢量。由于抽象是通過繼承器進行的,所以能在兩者方便地切換,對代碼的影響則顯得微不足道。</p><p>  最后,記住集合只是一個用來放置對象的儲藏所。如果那個儲藏所能滿足我們的所有需要,就完全沒必要關心它具體是如何實現(xiàn)的(這是大多數(shù)類型對象的一個基本概念)。如果在一個編程環(huán)境中工作,它由于其他因素(比如在Windows下運行,或者由垃圾收集器帶來了開銷)產(chǎn)生了內(nèi)在的開銷,那么矢量和鏈接列表

66、之間在系統(tǒng)開銷上的差異就或許不是一個大問題。我們可能只需要一種類型的序列。甚至可以想象有一個“完美”的集合抽象,它能根據(jù)自己的使用方式自動改變基層的實現(xiàn)方式。</p><p><b>  2 單根結構</b></p><p>  在面向?qū)ο蟮某绦蛟O計中,由于C++的引入而顯得尤為突出的一個問題是:所有類最終是否都應從單獨一個基礎類繼承。在Java中(與其他幾乎所有OO

67、P語言一樣),對這個問題的答案都是肯定的,而且這個終級基礎類的名字很簡單,就是一個“Object”。這種“單根結構”具有許多方面的優(yōu)點。</p><p>  單根結構中的所有對象都有一個通用接口,所以它們最終都屬于相同的類型。另一種方案(就象C++那樣)是我們不能保證所有東西都屬于相同的基本類型。從向后兼容的角度看,這一方案可與C模型更好地配合,而且可以認為它的限制更少一些。但假期我們想進行純粹的面向?qū)ο缶幊蹋?/p>

68、么必須構建自己的結構,以期獲得與內(nèi)建到其他OOP語言里的同樣的便利。需添加我們要用到的各種新類庫,還要使用另一些不兼容的接口。理所當然地,這也需要付出額外的精力使新接口與自己的設計方案配合(可能還需要多重繼承)。為得到C++額外的“靈活性”,付出這樣的代價值得嗎?當然,如果真的需要——如果早已是C專家,如果對C有難舍的情結——那么就真的很值得。但假如你是一名新手,首次接觸這類設計,象Java那樣的替換方案也許會更省事一些。</p&

69、gt;<p>  單根結構中的所有對象(比如所有Java對象)都可以保證擁有一些特定的功能。在自己的系統(tǒng)中,我們知道對每個對象都能進行一些基本操作。一個單根結構,加上所有對象都在內(nèi)存堆中創(chuàng)建,可以極大簡化參數(shù)的傳遞(這在C++里是一個復雜的概念)。</p><p>  利用單根結構,我們可以更方便地實現(xiàn)一個垃圾收集器。與此有關的必要支持可安裝于基礎類中,而垃圾收集器可將適當?shù)南l(fā)給系統(tǒng)內(nèi)的任何對象

70、。如果沒有這種單根結構,而且系統(tǒng)通過一個句柄來操縱對象,那么實現(xiàn)垃圾收集器的途徑會有很大的不同,而且會面臨許多障礙。</p><p>  由于運行期的類型信息肯定存在于所有對象中,所以永遠不會遇到判斷不出一個對象的類型的情況。這對系統(tǒng)級的操作來說顯得特別重要,比如違例控制;而且也能在程序設計時獲得更大的靈活性。</p><p>  3 集合庫與方便使用集合</p><p

71、>  由于集合是我們經(jīng)常都要用到的一種工具,所以一個集合庫是十分必要的,它應該可以方便地重復使用。這樣一來,我們就可以方便地取用各種集合,將其插入自己的程序。Java提供了這樣的一個庫,盡管它在Java 1.0和1.1中都顯得非常有限(Java 1.2的集合庫則無疑是一個杰作)。</p><p>  下溯造型與模板/通用性</p><p>  為了使這些集合能夠重復使用,或者“再生”

72、,Java提供了一種通用類型,以前曾把它叫作“Object”。單根結構意味著、所有東西歸根結底都是一個對象”!所以容納了Object的一個集合實際可以容納任何東西。這使我們對它的重復使用變得非常簡便。</p><p>  為使用這樣的一個集合,只需添加指向它的對象句柄即可,以后可以通過句柄重新使用對象。但由于集合只能容納Object,所以在我們向集合里添加對象句柄時,它會上溯造型成Object,這樣便丟失了它的身

73、份或者標識信息。再次使用它的時候,會得到一個Object句柄,而非指向我們早先置入的那個類型的句柄。所以怎樣才能歸還它的本來面貌,調(diào)用早先置入集合的那個對象的有用接口呢?</p><p>  在這里,我們再次用到了造型(Cast)。但這一次不是在分級結構中上溯造型成一種更“通用”的類型。而是下溯造型成一種更“特殊”的類型。這種造型方法叫作“下溯造型”(Downcasting)。舉個例子來說,我們知道在上溯造型的時

74、候,Circle(圓)屬于Shape(幾何形狀)的一種類型,所以上溯造型是安全的。但我們不知道一個Object到底是Circle還是Shape,所以很難保證下溯造型的安全進行,除非確切地知道自己要操作的是什么。</p><p>  但這也不是絕對危險的,因為假如下溯造型成錯誤的東西,會得到我們稱為“違例”(Exception)的一種運行期錯誤。我們稍后即會對此進行解釋。但在從一個集合提取對象句柄時,必須用某種方式

75、準確地記住它們是什么,以保證下溯造型的正確進行。</p><p>  下溯造型和運行期檢查都要求花額外的時間來運行程序,而且程序員必須付出額外的精力。既然如此,我們能不能創(chuàng)建一個“智能”集合,令其知道自己容納的類型呢?這樣做可消除下溯造型的必要以及潛在的錯誤。答案是肯定的,我們可以采用“參數(shù)化類型”,它們是編譯器能自動定制的類,可與特定的類型配合。例如,通過使用一個參數(shù)化集合,編譯器可對那個集合進行定制,使其只接

76、受Shape,而且只提取Shape。</p><p>  參數(shù)化類型是C++一個重要的組成部分,這部分是C++沒有單根結構的緣故。在C++中,用于實現(xiàn)參數(shù)化類型的關鍵字是template(模板)。Java目前尚未提供參數(shù)化類型,因為由于使用的是單根結構,所以使用它顯得有些笨拙。但這并不能保證以后的版本不會實現(xiàn),因為“generic”這個詞已被Java“保留到將來實現(xiàn)”(在Ada語言中,“generic”被用來實現(xiàn)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論