1. 程式人生 > >《java程式設計思想》--物件初始化和麵向物件特性

《java程式設計思想》--物件初始化和麵向物件特性

1.java類的初始化順序

(1).一個類中,初始化順序由變數在類中的宣告定義順序決定,成員變數初始化在方法呼叫之前,包括構造方法。

(2).靜態變數在整個儲存區只保留一份拷貝,本地變數不能使用靜態關鍵字,基本型別的靜態變數不需要初始化它會根據型別獲得初始化值。引用型別的靜態變數預設初始化為null。靜態變數的初始化發生在需要使用的時候一旦被初始化之後,靜態變數就不會再初始化。

(3).靜態初始化塊和靜態變數類似的執行也在構造方法之前,並且僅執行一次。

(4).動態初始化塊(與靜態初始化塊類似,只是沒有static關鍵字,即放在一對大括號中的程式碼塊)在靜態初始化塊初始化結束後執行,動態初始化塊每次建立新物件都會初始化一次。

(5).構造方法執行時先執行父類的構造方法後執行子類的構造方法。

(6).本地變數初始化最晚在方法中初始化。

綜述:類的初始化順序依次為

a.父類的靜態變數/靜態初始化塊;

b.子類類的靜態變數/靜態初始化塊;

c.父類的動態初始化塊、非構造方法和set方法的成員變數初始化

d.子類的動態初始化塊、非構造方法和set方法的成員變數初始化

e.父類的構造方法。

f.子類的構造方法。

g.父類本地變數。

h.子類的本地變數。

2.陣列初始化

Java中陣列初始化有以下3中方式

(1).陣列宣告時直接初始化,如int[] a = {1,2,3};

(2).動態陣列初始化,如int[] a = new int[]{1,2,3};

注意,動態陣列初始化時,不能在new()操作符中指定陣列的大小,即int a = new int[3]{1,2,3}的寫法是錯誤的陣列的大小由初始化陣列元素個數決定。

(3).固定長度陣列初始化,如int[] a = new int[3];  a[1] = 0;  a[2] = 1;  a[3] = 2;

注意固定長度大小的陣列初始化時不能大於所宣告的陣列長度,沒有宣告的陣列元素使用其預設值,如int預設為0物件型別的值為引用,預設為null.

3.java程式碼重用4中方式

java面向物件程式設計中提供瞭如下4中程式碼重用的方式

(1).組合

面向物件程式設計中最常用的程式碼複用方式,具體的方式是在一個物件中將另一個對,象引用最為成員變數,其最大的優點是既實現鬆散耦合,有可能提高程式碼複用率。

(2).繼承

面向物件程式設計中常用提高程式碼複用率的方法之一,適用於子類和父類是同一種抽象型別,具有共同的屬性情況。

使用繼承,子類可以複用父類除private私有房屋控制權限以為的所有屬性和方法、編譯器將父類封裝為子類物件內部的一個物件。

需要注意的是,呼叫子類初始化構造方法時,編譯器會確保首先呼叫父類的構造方法初始化父類,然後才初始化子類,如果父類中沒有預設的構造方法,即需要顯式傳入引數的構造方法時,子類必須通過super關鍵字顯式傳入引數呼叫父類的構造方法。

(3).委派

Java中不支援委派方式的程式碼複用,但是開發人員可以使用委派機制實現程式碼的重用。

委派是指java物件的所有方法其實都是委派呼叫另一個類的方法實現,但是當前類又不是所委派類的型別,因此使用繼承不太合適,解決方式和組合類似,將被委派類作為委派類的成員變數,委派類的方法直接呼叫被委派類物件應用的方法。

 (4).聯合使用組合和繼承方式

因為java中不允許多繼承,如果某種情況下,一個java類需要使用多個其他類功能,且該類和其中某個類具有很多共同屬性,即可以看作同一類,則可以使當前類繼承具體共同屬性的類,同時將其他類作為成員變數組合引用。

4.組合和繼承的區別

組合和繼承都可以複用程式碼,很多java程式設計師,甚至是架構師都分不清楚什麼情況下該使用組合,什麼情況下應該使用繼承,具體的區別如下,

(1).組合

組合通常是在一個類中想使用另一個類已有的特性,但是卻不想使用其介面。使用組合可以可以將一個類作為當前類的內嵌物件,這樣在當前類中就可以顯式地使用內嵌類已經實現的功能,與此同時又不會影響當前類的呼叫介面。

(2).繼承

繼承是隱式地使用被繼承類的功能,相當於提供了一個新版本的父類實現。使用繼承,子類不但可以複用父類的功能,同時還複用了父類的介面,子類和父類的對外呼叫介面相同的情況下適合使用繼承。使用繼承時,很多情況下需要向上型別轉換,即將子類看作其父類。在程式設計時到底選用組合方式還是繼承方式,一個簡單的判斷依據是是否需要向上型別轉換,如果需要就使用繼承,如果不需要,則選擇組合。

5.final方法

Java中使用final型別的方法有以下兩種原因,

(1).設計原因

 final型別的方法不允許其子類修改方法即不允許子類覆蓋父類的final方法。

(2).效率原因

在早期的java實現中,如果方法被宣告為final,編譯器將final方法呼叫編譯為內聯呼叫。 正常的方法呼叫是如果方法呼叫時,將當前的方法上下文保持到棧中,呼叫被呼叫的方法,然後在將呼叫上下文出棧恢復呼叫現場。

內聯呼叫是,如果方法呼叫時,將被呼叫方法體拷貝到當前呼叫的地方合併成一個方法體,這樣就避免因需要儲存方法呼叫執行緒而進行的進棧和出棧操作,可以提高效率。

新版的使用hotspot技術的java虛擬機器可以探測方法呼叫情況而做效率優化,final方法不再作為提高效率的手段唯一的作用是確保方法不被子類覆蓋。

注意,任何private的方法都是隱式的final型別,同final方法類似,private方法不能被子類所覆蓋,但是private比final更嚴格,基類的private方法對子類不可見private方法不再是介面的一部分。

6.多型性

面向物件程式設計中的多型和繼承往往是一起發揮作用的,使用繼承,所有的子類和父類使用相同的對外介面,而多型的基礎是晚繫結或動態繫結或執行時繫結,即物件引用使用基類型別,在編譯時編譯器無法確切知道到底呼叫哪一個具體類,只有在執行時,java虛擬機器才通過型別檢查確定呼叫物件的具體型別。

Java中預設物件引用全部是晚繫結,只有static和final型別的引用時早繫結或編譯時繫結。

多型的優勢是程式的可擴張性好,無論新增多少個子類,基類的介面都不用改變,只需要在子類對應方法中提供具體實現即可,也就是所謂的將程式變化的部分和程式保持不變的部分分離。

注意,只有正常的方法可以使用多型,欄位和靜態方法沒有多型機制。

構造方法也不支援多型機制,構造方法是隱式的static宣告。