複用類

複用代碼是Java衆多引人注目的功能之一,通過創建新類來複用代碼,使用類且不破壞現有的程序代碼。

組合

組合實現

將現有類型的對象置於新類型中,將該類型的作爲新類型底層實現的一部分加以複用。

初始化現有類對象

在上一篇博客中提到,類中的對象引用會被初始化爲null(未指定初始化值時),而如果此時爲它們調用方法時,都會得到一個異常,所以要對對象進行初始化。

對對象進行初始化的位置

1)在定義對象的地方進行初始化
2)在類的構造器中進行初始化
3)在正在使用這些對象之前,這也叫作“惰性初始化”

繼承

繼承實現

繼承複用的是接口,即導出類具有基類的接口。

初始化基類

簡介

當創建一個導出類的對象時,該對象包含了一個基類的子對象,該子對象被包裝在導出類對象內部。所以在導出類中正確地初始化基類子對象是十分重要的。

如何初始化

在到處類的構造器中調用基類的構造器執行初始化,並且基類構造器必須具有執行基類初始化所需要的所有知識和能力。
1. 缺省構造器(無參構造器)
如果開發者沒有指定具體的基類構造器,編譯器將會自動爲你合成一個缺省構造器。
2. 帶參數的構造器
如果類沒有缺省的無參構造器,或者想調用一個帶參數的基類構造器,就必須用super顯示的編寫調用基類構造器的語句,並配以適當的參數列表。注意:基類構造器必須是你在導出類構造器中要做的第一件事,不然編譯器會提醒你的:)

class Game() {
    Game(int i){
        System.out.println("Game constructor");
    }
}

calss BoardGame extends Game {
    BoardGame(int i) {
        super(i);
        System.out.println("BoardGame constructor");
    }
}

public class Chess extends BoardGame {
    Chess(){
        super(11);
        System.out.println("Chess constructor");
    }
    public static void main(String[] args){
        Chess x = Chess();
    }
}

/*控制檯顯示結果:
Game constructor
BoardGame constructor
Chess constructor
*/
包括繼承在內的初始化全程

在其他任何事物發生之前,將分配給對象的存儲空間初始化爲二進制的零(0和null)

對一個類進行加載的過程中,如果它有一個基類,那麼解釋器就會繼續加載(基類)(不管你是否打算產生一個該基類的對象,這都要發生),而如果這個基類還有自身的基類,那麼第二個基類就會被加載,如此類推。

接下來,根基類的static初始化被執行,然後是下一個導出類,以此類推。

至此,所有類都已被加載完畢,對象就可以被創建了。首先,創建根基類的子對象,根基類的成員進行初始化,然後調用根基類構造器(可以結合我這篇博客 初始化與清理),再接下來就是下一個導出類,以此類推。

protected關鍵字

基類中protected方法可以被導出類繼承。最好的方式是將字段保持爲private;你應當一直保留“更改底層實現”。然後通過protected方法來控制類的繼承者的訪問權限。

final關鍵字:無法修改

final數據

恆定不變的數據。對於基本類型,final使數值恆定不變;對於對象引用,final使引用恆定不變。

空白final

空白final在final的使用上提供了更大的靈活性,爲此,一個類中的final字段就可以做到根據對象而有所不同。但無論何時都必須確保空白final在使用前被初始化。

final參數

在參數列表中以聲明的方式將參數指明爲final。這意味着你無法在方法中更改參數引用的指向。

final方法

將方法鎖定,以防止繼承類的修改。(在設計類時,將方法指明爲final是明智的)
編譯器發現final方法時根據判斷直接將final方法的副本插入到當前代碼段而不是調用(相當於C++中的inline)。

final類

出於某種考慮,不打算對該類的設計做任何變動,或出於安全的考慮,不希望它有自子類。

確保正確清理

如果你想要某個類清理一些東西,請顯示地編寫一個方法來做這件事,客戶端程序員必須知曉他們必須調用這一方法且將這一清理動作置於finally子句中,以預防異常的出現。

在清理方法中還必須注意對基類清理方法和成員對象清理方法的調用順序,以防某個子對象依賴於另一個子對象情形的放生。首先,執行類的所有特定的清理方法,其順序同生成順序相反(通常這要求“基類”元素仍舊存活);然後,調用基類的清理方法(通過super.function_name(參數表列))。

除了內存以外,不要依賴垃圾回收器去做任何事。如果需要進行清理最好是編寫你自己的清理方法,不要依賴finalize()

增量開發

程序開發是一種增量過程,將項目看成是一種有機的、進化的生命體去培養。你的程序不該只關心”bit”,而應該通過生成和操作各種類型的對象,用來自問題空間的術語來表現一個模型。

向上轉型

程序代碼可以對基類和它的導出類起作用,將導出類引用轉換爲基類引用的動作叫做“向上轉型”。

基類名 i = 子類對象;

在向上轉型的過程中,類接口中唯一可能發生的事情就是丟失方法而不是獲取它們。

在組合和繼承中選擇

組合

通常用於想在新類中使用現有類的功能而非它的接口,即在新類中嵌入某個對象,讓其實現所需的功能,但新類的用戶看到的只是爲新類所定義的接口,而非所嵌入對象的接口。爲取得此效果,需在新類中嵌入一個現有類的private對象(但並非絕對,看具體開發情況)。

繼承

使用某個現有類,並開發一個它的特殊版本。通常,這意味着你在使用一個通用類,併爲了某種特殊需要而將其特殊化。

選擇

“is-a”(是一個)的關係用繼承來表達,”has-a”(有一個)的關係用組合來表達。

如果必須向上轉型,則繼承是必要的;否則,就該好好考慮是否需要繼承。

結合使用組合和繼承

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章