Time of Update: 2017-02-27
我們通常認為存取控制是“隱藏實施細節”的一種方式。將資料和方法封裝到類內後,可產生一種資料類型,它具有自己的特徵與行為。但由於兩方面重要的原因,訪問為那個資料類型加上了自己的邊界。第一個原因是規定客戶程式員哪些能夠使用,哪些不能。我們可在結構裡構建自己的內部機制,不用擔心客戶程式員將其當作介面的一部分,從而自由地使用或者“濫用”。這個原因直接導致了第二個原因:我們需要將介面同實施細節分離開。若結構在一系列程式中使用,但使用者除了將訊息發給publi
Time of Update: 2017-02-27
protected(受到保護的)訪問指示符要求大家提前有所認識。首先應注意這樣一個事實:為繼續學習本書一直到繼承那一章之前的內容,並不一定需要先理解本小節的內容。但為了保持內容的完整,這兒仍然要對此進行簡要說明,並提供相關的例子。protected關鍵字為我們引入了一種名為“繼承”的概念,它以現有的類為基礎,並在其中加入新的成員,同時不會對現有的類產生影響——我們將這種現有的類稱為“基礎類”或者“基本類&rdqu
Time of Update: 2017-02-27
private關鍵字意味著除非那個特定的類,而且從那個類的方法裡,否則沒有人能訪問那個成員。同一個包內的其他成員不能訪問private成員,這使其顯得似乎將類與我們自己都隔離起來。另一方面,也不能由幾個合作的人建立一個包。所以private允許我們自由地改變那個成員,同時毋需關心它是否會影響同一個包內的另一個類。預設的“友好”包訪問通常已經是一種適當的隱藏方法;請記住,對於包的使用者來說,是不能訪問一個“友好”成員的。這種效果往往能令人滿意,因為預
Time of Update: 2017-02-27
使用public關鍵字時,它意味著緊隨在public後面的成員聲明適用於所有人,特別是適用於使用庫的客戶程式員。假定我們定義了一個名為dessert的包,其中包含下述單元(若執行該程式時遇到困難,請參考第3章3.1.2小節“賦值”): //: Cookie.java// Creates a librarypackage c05.dessert;public class Cookie { public Cookie() {
Time of Update: 2017-02-27
針對類內每個成員的每個定義,Java訪問指示符poublic,protected以及private都置於它們的最前面——無論它們是一個資料成員,還是一個方法。每個訪問指示符都只控制著對那個特定定義的訪問。這與C++存在著顯著不同。在C++中,訪問指示符控制著它後面的所有定義,直到又一個訪問指示符加入為止。通過千絲萬縷的聯絡,程式為所有東西都指定了某種形式的訪問。在後面的小節裡,大家要學習與各類訪問有關的所有知識。首次從預設訪問開始。
Time of Update: 2017-02-27
Java已取消的一種特性是C的“條件編譯”,它允許我們改變參數,獲得不同的行為,同時不改變其他任何代碼。Java之所以拋棄了這一特性,可能是由於該特性經常在C裡用於解決跨平台問題:代碼的不同部分根據具體的平台進行編譯,否則不能在特定的平台上運行。由於Java的設計思想是成為一種自動跨平台的語言,所以這種特性是沒有必要的。然而,條件編譯還有另一些非常有價值的用途。一種很常見的用途就是調試代碼。調試特性可在開發過程中使用,但在發行的產品中卻無此功能。Alen
Time of Update: 2017-02-27
掌握前述的知識後,接下來就可以開始建立自己的工具庫,以便減少或者完全消除重複的代碼。例如,可為System.out.println()建立一個別名,減少重複鍵入的代碼量。它可以是名為tools的一個包(package)的一部分: //: P.java// The P.rint & P.rintln shorthandpackage com.bruceeckel.tools;public class P { public static void rint(Object obj)
Time of Update: 2017-02-27
我們用import關鍵字匯入一個完整的庫時,就會獲得“包”(Package)。例如:import java.util.*;它的作用是匯入完整的工具 +
Time of Update: 2017-02-27
“進行物件導向的設計時,一項基本的考慮是:如何將發生變化的東西與保持不變的東西分隔開。”這一點對於庫來說是特別重要的。那個庫的使用者(客戶程式員)必須能依賴自己使用的那一部分,並知道一旦新版本的庫出台,自己不需要改寫代碼。而與此相反,庫的建立者必須能自由地進行修改與改進,同時保證客戶程式員代碼不會受到那些變動的影響。為達到這個目的,需遵守一定的約定或規則。例如,庫程式員在修改庫內的一個類時,必須保證不刪除已有的方法,因為那樣做會造成客戶程式員代碼出現斷點。然而,相反的情況
Time of Update: 2017-02-27
作為初始化的一種具體操作形式,構建器應使大家明確感受到在語言中進行初始化的重要性。與C++的程式設計一樣,判斷一個程式效率如何,關鍵是看是否由於變數的初始化不正確而造成了嚴重的編程錯誤(臭蟲)。這些形式的錯誤很難發現,而且類似的問題也適用於不正確的清除或收尾工作。由於構建器使我們能保證正確的初始化和清除(若沒有正確的構建器調用,編譯器不允許對象建立),所以能獲得完全的控制權和安全性。在C++中,與“構建”相反的“破壞”(Destruction)工作
Time of Update: 2017-02-27
在Java裡可以方便地建立多維陣列: //: MultiDimArray.java// Creating multidimensional arrays.import java.util.*;public class MultiDimArray { static Random rand = new Random(); static int pRand(int mod) { return Math.abs(rand.nextInt()) % mod + 1; }
Time of Update: 2017-02-27
在C中初始化數組極易出錯,而且相當麻煩。C++通過“集合初始化”使其更安全(注釋⑥)。Java則沒有象C++那樣的“集合”概念,因為Java中的所有東西都是對象。但它確實有自己的數組,通過數組初始化來提供支援。數組代表一系列對象或者基礎資料型別 (Elementary Data
Time of Update: 2017-02-27
如果想自己為變數賦予一個初始值,又會發生什麼情況呢?為達到這個目的,一個最直接的做法是在類內部定義變數的同時也為其賦值(注意在C++裡不能這樣做,儘管C++的新手們總“想”這樣做)。在下面,Measurement類內部的欄位定義已發生了變化,提供了初始值: class Measurement { boolean b = true; char c = 'x'; byte B = 47; short s = 0xff; int i = 999;
Time of Update: 2017-02-27
Java盡自己的全力保證所有變數都能在使用前得到正確的初始化。若被定義成相對於一個方法的“局部”變數,這一保證就通過編譯期的出錯提示表現出來。因此,如果使用下述代碼:void f() {int i;i++;}就會收到一條出錯提示訊息,告訴你i可能尚未初始化。當然,編譯器也可為i賦予一個預設值,但它看起來更象一個程式員的失誤,此時預設值反而會“幫倒忙”。若強迫程式員提供一個初始值,就往往能夠幫他/她糾出程式裡的“臭蟲”。然而,
Time of Update: 2017-02-27
此時,大家可能已相信了自己應該將finalize()作為一種常規用途的清除方法使用。它有什麼好處呢?要記住的第三個重點是:垃圾收集只跟記憶體有關!也就是說,垃圾收集器存在的唯一原因是為了回收程式不再使用的記憶體。所以對於與垃圾收集有關的任何活動來說,其中最值得注意的是finalize()方法,它們也必須同記憶體以及它的回收有關。但這是否意味著假如對象包含了其他對象,finalize()就應該明確釋放那些對象呢?答案是否定的——垃圾收集器會負責釋放所有對象佔據的記憶體,無論
Time of Update: 2017-02-27
程式員都知道“初始化”的重要性,但通常忘記清除的重要性。畢竟,誰需要來清除一個int呢?但是對於庫來說,用完後簡單地“釋放”一個對象並非總是安全的。當然,Java可用垃圾收集器回收由不再使用的對象佔據的記憶體。現在考慮一種非常特殊且不多見的情況。假定我們的對象分配了一個“特殊”記憶體地區,沒有使用new。垃圾收集器只知道釋放那些由new分配的記憶體,所以不知道如何釋放對象的“特殊”記憶體。為解決這個問
Time of Update: 2017-02-27
如果有兩個同類型的對象,分別叫作a和b,那麼您也許不知道如何為這兩個對象同時調用一個f()方法:class Banana { void f(int i) { /* ... */ } }Banana a = new Banana(), b = new
Time of Update: 2017-02-27
我們很易對下面這些問題感到迷惑:為什麼只有類名和方法自變數列出?為什麼不根據傳回值對方法加以區分?比如對下面這兩個方法來說,雖然它們有同樣的名字和自變數,但其實是很容易區分的:void f() {}int f() {}若編譯器可根據上下文(語境)明確判斷出含義,比如在int
Time of Update: 2017-02-27
for迴圈在第一次反覆之前要進行初始化。隨後,它會進行條件測試,而且在每一次反覆的時候,進行某種形式的“步進”(Stepping)。for迴圈的形式如下:for(初始運算式; 布林運算式; 步進)語句無論初始運算式,布林運算式,還是步進,都可以置空。每次反覆前,都要測試一下布林運算式。若獲得的結果是false,就會繼續執行緊跟在for語句後面的那行代碼。在每次迴圈的末尾,會計算一次步進。for迴圈通常用於執行“計數”任務: //:
Time of Update: 2017-02-27
知道Java裡綁定的所有方法都通過後期綁定具有多型以後,就可以相應地編寫自己的代碼,令其與基礎類溝通。此時,所有的衍生類都保證能用相同的代碼正常地工作。或者換用另一種方法,我們可以“將一條訊息發給一個對象,讓對象自行判斷要做什麼事情。”在物件導向的程式設計中,有一個經典的“形狀”例子。由於它很容易用可視化的形式表現出來,所以經常都用它說明問題。但很不幸的是,它可能誤導初學者認為OOP只是為圖形化編程設計的,這種認識當然是錯誤的。形狀例子有一個基礎類