yooli88

          六章 復用類

                代碼的復用有兩種方法————1就是直接在新類中生成舊有的類的對象 (合成)2是創建一個新的類 這個類會全盤接受舊有的類 并且在不對舊有類修改的前提下 添加新的代碼(繼承)
                合成所使用的方法
                只要把對象的引用reference放到新的類里面就可以了。當primitive數據作為類的成員時候會自動初始化為零,對象的reference也會為null,這時候調用這個reference會拋出nullpoint異常。
             reference的初始化有以下三種方式:
             1 在定義對象的時候。這就意味著在調用構造函數之前,他們已經初始化完畢了。
             2在這個類的構造函數里。
             3在即將使用那個對象之前。如果碰到創建對象的代價很高,或者不是每次都需要創建對象的時候,這種做法就能降低程序的開銷。
                繼承所使用的方法
                繼承的時候 必須使用extends關鍵詞和基類的名字。之后新類就會自動獲得基類的全部成員和方法。繼承不會限定只能使用基類的方法。也可以往派生類里加入新的方法。
                基類的初始化
                當創建一個派生類的對象的時候,這個對象立門還有一個基類的對象。這個對象同基類自己創建的對象沒有任何的差別。只是從外面看來這個對象是被包裹在派生類的對象里面。
                基類的初始化只有一個方法能保證:調用基類的構造函數來進行初始化,只有這樣才能掌握怎樣才能正確地進行初始化的信息和權限。java會讓派生類的構造函數自動地調用基類的構造函數。
                帶參數的構造函數
                調用帶參數的構造函數必須使用super關鍵詞以及合適的參數明確調用基類的構造函數。
                確保進行妥善地清理
                一般情況下java會將需要清理的對象留給垃圾回收器去處理,它不會主動的進行清理。由于不知道垃圾回收器甚么時候啟動,也不知道會不會啟動,所有需要進行清理,就必須明確地寫一個專門干這件事情的方法,為了應付異常,還要將這個方法放入finally子句里面去。不要去調用finalize方法。
                用合成還是繼承
                一般來說,合成用于新類要使用舊類的功能,而不是其接口的場合,也就是說把對象嵌進去,用它來實現新類的功能,但用戶看到的是新類的接口,而不是嵌進去的對象的接口,因此在新類里嵌入private的舊類對象,有時為了讓用戶直接訪問新類的各個組成部分也可以嵌入public的舊類對象。通常都應該將基類的成員數據定義為privite類型。繼承表達的是一種“是(is-a)”關系,合成表達的是“有(has-a)”關系,對于一些需要對外部世界隱藏,但要對它的繼承類開放的基類 可以使用protected來定義那些開放的部分。最好的做法是,將數據成員設成private 的;你應該永遠保留修改底層實現的權利。然后用protected 權限的方法來控制繼承類的訪問權限。
                漸進式的開發
                繼承的優點之一就是,它支持漸進式的開發(incremental develop)。添加新的代碼的時候,不會給老代碼帶來bug;實際上新的bug 全都被圈在新代碼里。通過繼承已有的,已經能正常工作的類,然后再添加一些數據成員和方法(以及重新定義一些原有的方法),你可以不去修改那些可能還有人在用的老代碼,因而也就不會造成bug 了。一旦發現了bug,你就知道它肯定是在新代碼里。相比要去修改老代碼,新代碼會短很多,讀起來也更簡單。繼承實質上是在表達這樣一種關系:“新的類是一種舊的類”。
                上傳
                 繼承最重要的特征不在于它為新類提供了方法,而是它表達了新類同基類之間的關系。這種關系可以被歸納為一句話“新類就是一種原有的類。” (upcasting)”。上傳總是安全的,因為你是把一個較具體的類型轉換成較為一般的類型。也就是說派生類是基類的超集(superset)。它可能會有一些基類所沒有的方法,但是它最少要有基類的方法。在上傳過程中,類的接口只會減小,不會增大。這就是為什么編譯器會允許你不作任何明確的類型轉換或特殊表示就進行上傳的原因了。
                合成還是繼承,再探討
                在判斷該使用合成還是繼承的時候,有一個最簡單的辦法,就是問一下你是不是會把新類上傳給基類。如果你必須上傳,那么繼承就是必須的,如果不需要上傳,那么就該再看看是不是應該用繼承了。
                final 關鍵詞
                final 的三種用途:數據(data),方法(method)和類(class)。
          Final 的數據
                很多編程語言都有通知編譯器“這是段『常量(constant)』 數據”的手段。常量能用于下列兩種情況:
          1. 可以是“編譯時的常量(compile-time constant)”,這樣就再也不能改了。
          2. 也可以是運行時初始化的值,這個值你以后就不想再改了。
          如果是編譯時的常量,編譯器會把常量放到算式里面;這樣編譯的時候就能進行計算,因此也就降低了運行時的開銷。在Java 中這種常量必須是primitive 型的,而且要用final 關鍵詞表示。這種常量的賦值必須在定義的時候進行。
                 一個既是static 又是final 的數據成員會只占據一段內存,并且不可修改。
                當final 不是指primitive,而是用于對象的reference 的時候,意思就有點搞了。對primitive 來說,final 會將這個值定義成常量,但是對于對象的reference 而言,final 的意思則是這個reference 是常量。初始化的時候,一旦將reference 連到了某個對象,那么它就再也不能指別的對象了。但是這個對象本身是可以修改的;Java 沒有提供將某個對象作成常量的方法。(但是你可以自己寫一個類,這樣就能把類當做常量了。)這種局限性也體現在數組上,因為它也是一個對象。
                空白的final 數據 (Blank finals)
                Java 能讓你創建“空白的final 數據(blank finals)”,也就是說把數據成員聲明成final 的,但卻沒給初始化的值。碰到這種情況,你必須先進行初始化,再使用空白的final 數據成員,而且編譯器會強制你這么做。不過,空白的final 數據也提供了一種更為靈活的運用final 關鍵詞方法,比方說,現在對象里的final 數據就能在保持不變性的同時又有所不同了。
                你一定得為final 數據賦值,要么是在定義數據的時候用一個表達式賦值,要么是在構造函數里面進行賦值。為了確保final 數據在使用之前已經進行了初始化,這一要求是強制性的。
                Final 的參數
                Java 允許你在參數表中聲明參數是final 的,這樣參數也編程final了。也就是說,你不能在方法里讓參數reference 指向另一個對象了。
                Final 方法
          使用final 方法的目的有二。第一,為方法上“鎖”,禁止派生類進行修改。這是出于設計考慮。當你希望某個方法的功能,能在繼承過程中被保留下來,并且不被覆寫,就可以使用這個方法。
          第二個原因就是效率。如果方法是final 的,那么編譯器就會把調用轉換成“內聯的(inline)”。當編譯器看到要調用final 方法的時候,它就會(根據判斷)舍棄普通的,“插入方法調用代碼的”編譯機制(將參數壓入棧,然后跳去執行要調用的方法的代碼,再跳回來清空棧,再處理返回值),相反它會用方法本身的拷貝來代替方法的調用。當然如果方法很大,那么程序就會膨脹得很快,于是內聯也不會帶來什么性能的改善,因為這種改善相比程序處理所耗用的時間是微不足道的。Java 的設計者們暗示過,Java 的編譯器有這個功能,可以智能地判斷是不是應該將final 方法做成內聯的。不過,最好還是把效率問題留給編譯器和JVM去處理,而只把final 用于要明確地禁止覆寫的場合。
          final 和private
          private 方法都隱含有final 的意思。由于你不能訪問private 的方法,因此你也不能覆寫它。你可以給private 方法加一個final 修飾符,但是這樣做什么意義也沒有。這個問題有可能會造成混亂,因為即使你覆寫了一個private 方法(它隱含有final 的意思),看上去它還是可以運行的,而且編譯器也不會報錯。
                只有是基類接口里的東西才能被“覆寫”。也就是說,對象應該可以被上傳到基類,然后再調用同一個方法(這一點要到下一章才能講得更清楚。)如果方法是private 的,那它就不屬于基類的接口。它只能算是被類隱藏起來的,正好有著相同的名字的代碼。如果你在派生類里創建了同名的public 或protected,或package 權限的方法,那么它們同基類中可能同名的方法,沒有任何聯系。你并沒有覆寫那個方法,你只是創建了一個新的方法。由于private 方法是無法訪問的,實際上是看不見的,因此這么作除了會影響類的代碼結構,其它什么意義都沒有。
                Final 類
                把整個類都定義成final 的(把final 關鍵詞放到類的定義部分的前面)就等于在宣布,你不會去繼承這個類,你也不允許別人去繼承這個類。換言之,出于類的設計考慮,它再也不需要作修改了,或者從安全角度出發,你不希望它再生出子類。
                注意,final 類的數據可以是final 的,也可以不是final 的,這要由你來決定。無論類是不是final 的,這一條都適用于“將final 用于數據的”場合。但是,由于final 類禁止了繼承,覆寫方法已經不可能了,因此所有的方法都隱含地變成final 了。你可以為final 類的方法加一個final 修飾符,但是這一樣沒什么意義。
                小心使用final
                看來,設計類的時候將方法定義成final 的,會是一個很明智的決定。可能你會覺得沒人會要覆寫你的方法。有時確實是這樣。

          posted on 2007-06-28 19:20 迷茫在java的世界里 閱讀(187) 評論(0)  編輯  收藏 所屬分類: think in java 學習筆記


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 嘉荫县| 化州市| 海安县| 清苑县| 宣武区| 白玉县| 保靖县| 泗洪县| 靖州| 康定县| 宣武区| 山东省| 郴州市| 芒康县| 盐池县| 开化县| 招远市| 南郑县| 双辽市| 新蔡县| 岑巩县| 凯里市| 凤冈县| 汝城县| 双鸭山市| 宁乡县| 武穴市| 南安市| 图木舒克市| 广灵县| 云龙县| 辰溪县| 海兴县| 察雅县| 神池县| 莱州市| 靖边县| 通渭县| 公主岭市| 玉林市| 湘乡市|