1. 程式人生 > >JAVA程式設計思想學習 --- 第二章 (一切都是物件)

JAVA程式設計思想學習 --- 第二章 (一切都是物件)

1.程式執行時,我們資料儲存的地方     (1) 暫存器這是最快的儲存區域,因為它位於和其他所有儲存方式不同的地方:處理器內部。然而,暫存器的數量十分有限,所以暫存器是根據需要由編譯器分配。我們對此沒有直接的控制權,也不可能在自己的程式裡找到暫存器存在的任何蹤跡。     (2) 堆疊駐留於常規 RAM(隨機訪問儲存器)區域,但可通過它的“堆疊指標”獲得處理的直接支援。堆疊指標若向下移,會建立新的記憶體;若向上移,則會釋放那些記憶體。這是一種特別快、特別有效的資料儲存方式,僅次於暫存器。建立程式時, Java 編譯器必須準確地知道堆疊內儲存的所有資料的“長度”以及“存 在時間”。這是由於它必須生成相應的程式碼,以便向上和向下移動指標。這一限制無疑影響了程式的靈活性,所以儘管有些 Java 資料要儲存在堆疊裡—— 特別是物件控制代碼,但 Java 物件並不放到其中。     (3)
一種常規用途的記憶體池(也在 RAM 區域),其中儲存了 Java 物件。和堆疊不同,“記憶體堆”或“堆”( Heap)最吸引人的地方在於編譯器不必知道要從堆裡分配多少儲存空間,也不必知道儲存的資料要在堆裡停留多長的時間。因此,用堆儲存資料時會得到更大的靈活性。要求建立一個物件時,只需用new 命 令編制相關的程式碼即可。執行這些程式碼時,會在堆裡自動進行資料的儲存。當然,為達到這種靈活性,必然會付出一定的代價:在堆裡分配儲存空間時會花掉更長的時間!     (4) 靜態儲存這兒的“靜態”( Static)是指“位於固定位置”(儘管也在 RAM 裡)。程式執行期間,靜態儲存的資料將隨時等候呼叫。可用static
關鍵字指出一個物件的特定元素是靜態的。但 Java 物件本身永遠都不會置入靜態儲存空間。     (5) 常數儲存常數值通常直接置於程式程式碼內部。這樣做是安全的,因為它們永遠都不會改變。有的常數需要嚴格地保護,所以可考慮將它們置入只讀儲存器( ROM)。     (6) 非 RAM 儲存若資料完全獨立於一個程式之外,則程式不執行時仍可存在,並在程式的控制範圍之外。其中兩個最主要的例子便是“流式物件”和“固定物件”。對於流式物件,物件會變成位元組流,通常會發給另一臺機器。而對於固定物件,物件儲存在磁碟中。即使程式中止執行,它們仍可保持自己的狀態不變。對於這些型別的資料儲存,一個特別有用的技巧就是它們能存在於其他媒體中。一旦需要,甚至能將它們恢復成普通的、基於 RAM 的物件。 Java 1.1 提供了對 Lightweight persistence 的支援。未來的版本甚至可能提供更完整的方案 2.特殊情況:基本資料型別
    有一系列類需特別對待;可將它們想象成“基本”、“主要”或者“主”( Primitive)型別,進行程式設計時要頻繁用到它們。之所以要特別對待,是由於用 new 建立物件(特別是小的、簡單的變數)並不是非常有效,因為 new 將物件置於“堆”裡。對於這些型別, Java 採納了與 C 和 C++相同的方法。也就是說,不是用new 建立變數,而是建立一個並非控制代碼的“自動”變數。這個變數容納了具體的值,並置於堆疊中,能夠更高效地存取     Java 決定了每種主要型別的大小。就象在大多數語言裡那樣,這些大小並不隨著機器結構的變化而變化。這種大小的不可更改正是 Java 程式具有很強移植能力的原因之一。      下面是基本資料型別的大小,最大值,最小值,封裝型別,以及預設值等     3.Java的陣列      建立物件陣列時,實際建立的是一個控制代碼陣列。而且每個控制代碼都會自動初始化成一個特殊值,並帶有自己的 關鍵字: null(空)。一旦 Java 看到 null,就知道該控制代碼並未指向一個物件。正式使用前,必須為每個句 柄都分配一個物件。若試圖使用依然為 null 的一個控制代碼,就會在執行期報告問題。因此,典型的陣列錯誤在 Java 裡就得到了避免。      也可以建立主型別陣列。同樣地,編譯器能夠擔保對它的初始化,因為會將那個陣列的記憶體劃分成零。 4.物件的欄位和方法      定義一個類時(我們在 Java 裡的全部工作就是定義類、製作那些類的物件以及將訊息發給那些物件),可在自己的類裡設定兩種型別的元素資料成員(有時也叫“欄位”)以及成員函式(通常叫“方法”)。其 中,資料成員是一種物件(通過它的控制代碼與其通訊),可以為任何型別。它也可以是主型別(並不是控制代碼) 之一。如果是指向物件的一個控制代碼,則必須初始化那個控制代碼,用一種名為“構建器”(第4 章會對此詳述)的特殊函式將其與一個實際物件連線起來(就象早先看到的那樣,使用new 關鍵字)。但若是一種主型別, 則可在類定義位置直接初始化(正如後面會看到的那樣,控制代碼亦可在定義位置初始化)。每個物件都為自己的資料成員保有儲存空間;資料成員不會在物件之間共享。      我們建立類時會指出那個類的物件的外觀與行為。除非用new 建立那個類的一個物件,否則實際上並 未得到任何東西。只有執行了 new 後,才會正式生成資料儲存空間,並可使用相應的方法。      一旦將變數作為類成員使用,就要特別注意由 Java 分配的預設值。這樣做可保證主型別的成員變數肯定得到 了初始化( C++不具備這一功能),可有效遏止多種相關的程式設計錯誤。 然而,這種保證卻並不適用於“區域性”變數—— 那些變數並非一個類的欄位。所以,假若在一個函式定義中 寫入下述程式碼:     int x;      那麼 x 會得到一些隨機值(這與 C 和 C++是一樣的),不會自動初始化成零。我們責任是在正式使用x 前分 配一個適當的值。如果忘記,就會得到一條編譯期錯誤,告訴我們變數可能尚未初始化。這種處理正是 Java 優於 C++的表現之一。許多 C++編譯器會對變數未初始化發出警告,但在 Java 裡卻是錯誤。 5.類名字的可見性      在所有程式設計語言裡,一個不可避免的問題是對名字或名稱的控制假設您在程式的某個模組裡使用了一個名字,而另一名程式設計師在另一個模組裡使用了相同的名字。此時,如何區分兩個名字,並防止兩個名字互 相沖突呢?這個問題在 C 語言裡特別突出。因為程式未提供很好的名字管理方法。 C++的類(即 Java 類的基 礎)巢狀使用類裡的函式,使其不至於同其他類裡的巢狀函式名衝突。然而, C++仍然允許使用全域性資料以及 全域性函式,所以仍然難以避免衝突。為解決這個問題, C++用額外的關鍵字引入了“名稱空間”的概念。      由於採用全新的機制,所以 Java 能完全避免這些問題。為了給一個庫生成明確的名字,採用了與Internet 域名類似的名字。事實上, Java 的設計者鼓勵程式設計師反轉使用自己的 Internet 域名,因為它們肯定是獨一 無二的。由於我的域名是 BruceEckel.com,所以我的實用工具庫就可命名為 com.bruceeckel.utility.foibles。反轉了域名後,可將點號想象成子目錄。 在 Java 1.0 和 Java 1.1 中,域副檔名 com, edu, org, net 等都約定為大寫形式。所以庫的樣子就變成: COM.bruceeckel.utility.foibles。然而,在 Java 1.2 的開發過程中,設計者發現這樣做會造成一些問題。 所以目前的整個軟體包都以小寫字母為標準。      Java 的這種特殊機制意味著所有檔案都自動存在於自己的名稱空間裡。而且一個檔案裡的每個類都自動獲得 一個獨一無二的識別符號(當然,一個檔案裡的類名必須是唯一的)。 6.使用其他的元件(其他類)      一旦要在自己的程式裡使用一個預先定義好的類,編譯器就必須知道如何找到它。當然,這個類可能就在發 出調用的那個相同的原始碼檔案裡。如果是那種情況,只需簡單地使用這個類即可—— 即使它直到檔案的後面 仍未得到定義。 Java 消除了“向前引用”的問題,所以不要關心這些事情。      但假若那個類位於其他檔案裡呢?您或許認為編譯器應該足夠“聯盟”,可以自行發現它。但實情並非如 此。假設我們想使用一個具有特定名稱的類,但那個類的定義位於多個檔案裡。或者更糟,假設我們準備寫      一個程式,但在建立它的時候,卻向自己的庫加入了一個新類,它與現有某個類的名字發生了衝突。 為解決這個問題,必須消除所有潛在的、糾纏不清的情況。為達到這個目的,要用import 關鍵字準確告訴 Java 編譯器我們希望的類是什麼。 import 的作用是指示編譯器匯入一個“包” —— 或者說一個“類庫”(在 其他語言裡,可將“庫”想象成一系列函式、資料以及類的集合。但請記住, Java 的所有程式碼都必須寫入一 個類中)。      大多數時候,我們直接採用來自標準 Java 庫的元件(部件)即可,它們是與編譯器配套提供的。使用這些組 件時,沒有必要關心冗長的保留域名;舉個例子來說,只需象下面這樣寫一行程式碼即可: import java.util.Vector;      它的作用是告訴編譯器我們想使用 Java 的 Vector 類。然而, util 包含了數量眾多的類,我們有時希望使用 其中的幾個,同時不想全部明確地宣告它們。 為達到這個目的,可使用“ *”萬用字元。如下所示: import java.util.*;      需匯入一系列類時,採用的通常是這個辦法。應儘量避免一個一個地匯入類。 7.static關鍵字      通常,我們建立類時會指出那個類的物件的外觀與行為。除非用new 建立那個類的一個物件,否則實際上並 未得到任何東西。只有執行了 new 後,才會正式生成資料儲存空間,並可使用相應的方法。      但在兩種特殊的情形下,上述方法並不堪用。一種情形是隻想用一個儲存區域來儲存一個特定的資料—— 無 論要建立多少個物件,甚至根本不建立物件。另一種情形是我們需要一個特殊的方法,它沒有與這個類的任 何物件關聯。也就是說,即使沒有建立物件,也需要一個能呼叫的方法。為滿足這兩方面的要求,可使用 static(靜態)關鍵字一旦將什麼東西設為 static,資料或方法就不會同那個類的任何物件例項聯絡到一 起。 它意味著一個特定的方法沒有 this。我們不可從一個 static 方法內部發出對非 static 方法的呼叫,儘管反過來說是可以的。 而且在沒有任何物件的前提下,我們可針對類本身發出對一個 static 方法的呼叫。事實上,那正是 static 方法最基本的意義。它就好象我們建立一個全域性函式的等價物(在C 語言中)。除了全域性函式不允許在 Java 中使用以外,若將一個 static 方法置入一個類的內部,它就可以訪問其他 static 方法以及 static 欄位。 8.public static void main(String[] args)的解釋        類名與檔案是一樣的若想現在這樣建立一個獨立的程式,檔案中的一個類必須與檔案同名(如果沒這樣 做,編譯器會及時作出反應)。類裡必須包含一個名為 main()的方法,形式如下: public static void main(String[] args) {      其中,關鍵字“ public”意味著方法可由外部世界呼叫(第 5 章會詳細解釋)。main()的自變數是包含了 String 物件的一個數組args 不會在本程式中用到,但需要在這個地方列出,因為它們儲存了在命令列呼叫 的自變數。 9.註釋和嵌入文件      Java 裡有兩種型別的註釋。第一種是傳統的、 C 語言風格的註釋,是從 C++繼承而來的。這些註釋用一個 “ /*”起頭,隨後是註釋內容,並可跨越多行,最後用一個“ */”結束。兩種註釋示例 第一種: // 這是一條單行註釋 第二種 /* 這是 * 一段註釋, * 它跨越了多個行 */      對於 Java 語言,最體貼的一項設計就是它並沒有打算讓人們為了寫程式而寫程式—— 人們也需要考慮程式的 文件化問題。對於程式的文件化,最大的問題莫過於對文件的維護。若文件與程式碼分離,那麼每次改變程式碼 後都要改變文件,這無疑會變成相當麻煩的一件事情。解決的方法看起來似乎很簡單:將程式碼同文檔“鏈 接”起來。為達到這個目的,最簡單的方法是將所有內容都置於同一個檔案。然而,為使一切都整齊劃一, 還必須使用一種特殊的註釋語法,以便標記出特殊的文件;另外還需要一個工具,用於提取這些註釋,並按 有價值的形式將其展現出來。這些都是 Java 必須做到的。      用於提取註釋的工具叫作 javadoc。它採用了部分來自 Java 編譯器的技術,查詢我們置入程式的特殊註釋標 記。它不僅提取由這些標記指示的資訊,也將毗鄰註釋的類名或方法名提取出來。這樣一來,我們就可用最 輕的工作量,生成十分專業的程式文件。      javadoc 輸出的是一個 HTML 檔案,可用自己的 Web 瀏覽器檢視。該工具允許我們建立和管理單個原始檔,並 生動生成有用的文件。由於有了 jvadoc,所以我們能夠用標準的方法建立文件。而且由於它非常方便,所以 我們能輕鬆獲得所有 Java 庫的文件。 @ see :引用其他類 類文件標記: @version 版本資訊 其中,“版本資訊”代表任何適合作為版本說明的資料。若在 javadoc 命令列使用了“ -version”標記,就 會從生成的 HTML 文件裡提取出版本資訊。 @author 作者資訊 其中,“作者資訊”包括您的姓名、電子函件地址或者其他任何適宜的資料。若在javadoc 命令列使用了“ - author”標記,就會專門從生成的 HTML 文件裡提取出作者資訊。 方法文件標記 @param 引數名 說明 其中,“引數名”是指引數列表內的識別符號,而“說明”代表一些可延續到後續行內的說明文字。一旦遇到 一個新文件標記,就認為前一個說明結束。可使用任意數量的說明,每個引數一個。 @return 說明 其中,“說明”是指返回值的含義。它可延續到後面的行內。 @exception 完整類名 說明 其中,“完整類名”明確指定了一個違例類的名字,它是在其他某個地方定義好的。而“說明”(同樣可以 延續到下面的行)告訴我們為什麼這種特殊型別的違例會在方法呼叫中出現。 @deprecated 這是 Java 1.1 的新特性。該標記用於指出一些舊功能已由改進過的新功能取代。該標記的作用是建議使用者不 必再使用一種特定的功能,因為未來改版時可能摒棄這一功能。若將一個方法標記為@deprecated,則使用該 方法時會收到編譯器的警告。 10.編碼樣式      一個非正式的 Java 程式設計標準是大寫一個類名的首字母。若類名由幾個單詞構成,那麼把它們緊靠到一起(也 就是說,不要用下劃線來分隔名字)。此外,每個嵌入單詞的首字母都採用大寫形式。例如: class AllTheColorsOfTheRainbow { // ...}      對於其他幾乎所有內容:方法、欄位(成員變數)以及物件控制代碼名稱,可接受的樣式與類樣式差不多,只是 識別符號的第一個字母採用小寫。 最近在看JAVA程式設計思想(第四版)這本書,將書中的一些知識點容易遇到或者混淆的概念記錄下來,只是作為備忘,希望也能幫到需要的人,特此申明.