《麵向對象的思考過程(原書第4版)》一3.3 作用域的重要性
本節書摘來自華章出版社《麵向對象的思考過程(原書第4版)》一書中的第3章,第3.3節,[美] 馬特·魏斯費爾德(Matt Weisfeld) 著黃博文 譯更多章節內容可以訪問雲棲社區“華章計算機”公眾號查看。
3.3 作用域的重要性
單個類可以實例化出多個對象。每個對象有唯一的標識和狀態。這點很關鍵。會給每個單獨構造的對象會分配獨立的內存。然而,一個類實例化的多個對象可以共享類中一些屬性和方法,從而共享為這些屬性和方法分配的內存。
共享方法
構造函數是一個被類的所有實例共享的方法,這是共享方法的一個好例子。
方法代表了對象的行為,屬性代表了對象的狀態。對象有三種屬性:
局部屬性。
對象屬性。
類屬性。
3.3.1 局部屬性?
方法method1包含了一個名為count的局部變量。隻能在method1中訪問該整數。method2甚至不知道整數count的存在。?
基於該點,我們引入了一個非常重要的概念:作用域。屬性(和方法)存在於特定的作用域中。在本例中,整數count存在於method1的作用域中。在Java、C#、C++和Objective-C中,使用花括號({})來定義作用域。在Number類中,通過匹配花括號可以得到幾個作用域。
類自身擁有作用域。類的每個實例(即每個對象)也有自己的作用域。method1和method2也擁有各自的作用域。因為count存活於method1的花括號中,所以當調用method1時,會創建count的一個副本。當method1終結時,會刪除count的這個副本。
為了讓事情更有趣,請看以下代碼:
在本例中有兩個count的副本存在於該類中。請記住,method1和method2擁有各自的作用域。因此編譯器可以簡單通過分辨count所在的方法來確定對count的可訪問性。你可以這樣認為:
就編譯器來說,即使這兩個屬性的名字是一樣的,也很容易區分彼此。這就好比兩個人擁有相同的名,但是他們的姓不一樣,所以他們是獨立的個體。
3.3.2 對象屬性
在很多設計場景中,可以在同一個對象中的多個方法中共享屬性。例如圖3-6,從單個類中構造出了三個對象。請看以下代碼:
注意,該類中對屬性count的聲明放在方法method1和method2的作用域之外。然而,它在該類的作用域之內。因此,count對於method1和method2都是可見的。(基本上,該類中的所有方法都可以訪問這個屬性)。請注意,兩個方法中的代碼都指定了count的值。整個對象隻有一份count副本,所以兩個賦值行為操作的是內存中的同一份副本。然而,不同的對象並不共享count的副本。

我們創建了Number類的三個實例副本來進行演示:
number1、number2、number3這三個對象都是單獨構造的,而且都單獨分配了自己的資源。整數count有三個獨立的實例。當number1修改了自身的屬性count時,不會影響對象number2和number3中的count副本。因此整數count是對象屬性。
可以通過以下代碼來理解作用域:
每個對象對於count有三個完全獨立的內存位置。對象Number擁有一份副本,method1()和method2()也各自擁有一份副本。
為了從其中一個方法(比如method1())訪問對象屬性,可以使用一個基於C語言的名為this的指針:
請注意,一些代碼有些奇怪:
以上代碼需要使用this關鍵字。我們必須使用它。這裏使用this關鍵字指導編譯器訪問對象屬性count,而不是方法體中的局部變量count。
注意
關鍵字this是對當前對象的一個引用。
3.3.3 類屬性
正如之前提到的一樣,兩個或多個對象之間可以共享屬性。在Java、C#、C++和Objective-C中,可以把屬性設置為static:
聲明count為static類型,那麼從該類中實例化的所有對象隻會為該屬性分配一塊單獨的內存。即該類的所有對象對count使用同一塊內存位置。事實上,每個類隻有一個副本,該類的所有對象共享該副本(如圖3-7所示)。這與我們在麵向對象設計中所說的全局數據很相似。

類屬性具有很多實用的用途;然而,你必須要了解潛在的同步問題。我們來初始化兩個Count對象:
為便於討論,Count1對象使用count來記錄計算機屏幕上的像素。如果Count2對象決定使用屬性count來記錄綿羊個數就會出問題。Count2記下了第一隻羊的瞬間,Count1保存的數據會丟失掉。
最後更新:2017-05-25 11:31:49