MarsEdit粘代碼好麻煩,全部代碼交給github:https://github.com/lozybean/MyJavaLearninghtml
複用一個類經常使用的兩種方式:組合、繼承;java
將對象引用置於新類中,新類就完成了這些對象的複用;ios
Java中,每一個非基本對象都有一個toString方法,當須要一個String對象時直接調用;對象的引用在類的定義中會被初始化爲null;引用初始化能夠在四個地方進行:對象定義時 > 實例初始化 > 類構造器中 > 使用對象以前(按初始化順序排列);示例代碼git
使用extends關鍵字繼承一個類的成員(除private以外);github
從示例代碼中,能夠看到main方法能夠存在於多個類中,這樣的寫法爲了單元測試更加簡便易行(翹首以待),即使Cleanser並非public類,可是public main()仍然能夠被外部調用;即:即便一個類只具備包訪問權限,其public main()仍然是可訪問的;編程
Detergent類使用extends繼承了Cleanser,即實現了Cleanser中全部可繼承方法的複用;不只如此,還能夠在Detergent類中對某些方法進行改寫,如scrub()方法,在改寫過程當中,若是須要調用基類的同名方法,則使用super.scrub()來調用;固然,Detergent類能夠定義除了繼承來的方法以外的方法;swift
在子類建立對象以前,會先進行基類的初始化;也就是說,當建立了一個子類的對象時,不只僅複製了基類的接口,會包含一個基類的子對象,該子對象包裝在子類的對象內部,並具備直接使用基類建立的對象同樣的屬性;如:示例代碼中,在Cartoon類構造器能夠訪問到對象以前,基類的構造器就能夠訪問到,而且完成初始化;即便沒有Cartoon構造器,編譯器也會產生一個默認的構造器,而且調用基類的構造器;而且能夠看到,當C類繼承A類,而且有一個B類的對象時,若是實例化C類對象,則會先調用A類的構造器,再調用B類構造器,最後調用自身構造器(若是沒有定義的話,則不會調用);編程語言
當基類中的構造器不是默認構造器,而是帶參數的構造器,而且沒有默認構造器時,則必須在子類中使用super(args)調用該構造器,並傳入相應的參數列表,不然沒法完成基類的構造,編譯器報錯;示例代碼ide
子類中的構造器執行順序爲:包含其餘類對象的構造器(當該對象是直接初始化時,若是在構造器中初始化,則和子類構造器一個順序級別)、基類構造器、子類構造器;若前二者沒有默認的構造器,則包含其餘類對象必須正確調用構造器,基類必須使用super(args)正確調用構造器;示例代碼函數
繼承過程的初始化過程爲:1. 加載基類、基類的static初始化;2. 若是加載基類的過程當中,發現還有基類,則先加載該基類,執行static初始化,而後再回到第一個基類中的static初始化過程,依次類推;3. 基類加載完成後建立對象,調用基類構造器(生成隱含子對象),而後再調用子類構造器,完成對象建立;如示例代碼中,執行Beetle.main()時,先加載Beetle類,發現有一個基類Insect,並加載該基類,以及其static成員的初始化,而後完成Beetle類的static初始化,接着纔是順序執行println語句,以後新建一個Beetle對象,先進行基類的數據成員加載,而後調用基類的構造函數,接着進行子類的數據成員加載,最後調用子類的構造函數;只有這樣的過程,才能保證子類所依賴的基類成員被正確初始化;
java並無提供代理的直接支持,將一個成員對象置於所要構造的類中,但同時又在新類中暴露該成員對象的全部方法;即在新類中添加一個想要繼承類的對象,而後在新類中實現該對象的方法,此時,使用該代理建立的對象即可經過實現的方法擁有和繼承類相同的接口;不一樣的是,代理能夠選擇繼承方法中的某個子集,因此具備更加靈活的控制力;示例代碼
java中,析構函數能夠在對象被銷燬時自動調用(finalize()方法),當須要在一個類的生命週期內執行一些必須的清理活動,除了finalize()方法外,並不能知道java在什麼時候銷燬一個對象,可是將該方法置於finally子句中,能夠保證該方法被調用(不管是正常執行仍是異常退出);即:
try{
// … do something
} finally{
x.dispose(); //這裏是本身實現的清理方法,該方法必定會被執行;
}
在實現清理方法時,必須注意基類和成員對象清理方法的調用順序,防止某個子對象依賴於某個子對象的情形發生;(通常來講,按照構造器調用的相反順序),如:示例代碼
在java中重載某個基類的方法時,並不須要(如C++中)將該方法屏蔽,而可使用基類中的全部重載方法;如:示例代碼中,Bart重載了方法doh,並使用了新的參數列表,可是Bart類實例化的對象仍然能夠調用Homer中的同名方法;
這樣的特性有時會引發迷惑,因此Java SE5新增長了@Override註釋(並非關鍵字),當給某個方法添加該註釋後,若是子類直接調用該方法則會產生錯誤,必須重載該方法才能正確使用;(忽然明白swift ios開發學習時用到的各類override)
組合和繼承雖然均可以複用對象,組合是顯式地將子對象放到新類中,而繼承是隱式地將子對象放到新類中;
組合經常使用於想在新類中實現現有類的功能,而非它的接口這種情形,即,在新類中嵌入某個對象,讓該對象來實現須要的功能,因爲新類的用戶想要看到的是新類的接口,而非嵌入對象的接口,因此須要用private來嵌入該對象;但有時,容許新類中的組合成分可見是頗有意義的,此時應該使用public來嵌入該對象;
繼承經常使用於要使用某個現有的類,並開發它的一個特殊版本;繼承能夠得到基類中的protected域,這是組合和代理所沒法完成的;繼承更加劇要的方面是表現:新類是現有類的一種類型(書上翻譯的名詞,感受容易混餚,這裏的類型不是編程語言中的術語,而是天然語言中的類型),經過繼承能夠實現向上轉型,即在導論中提到的例子,一個基類的方法能夠直接處理子類,這樣作的好處是將方法通用化,實現特殊化;若是設計上沒有明確要求向上轉型的操做,則應該慎重考慮使用繼承,而經常使用組合;
而代理則是使用組合實現子對象的功能時,添加相應的接口方法,是對基類的某部分進行從新實現;
final關鍵字指沒法改變的;
當final用於數據時,表示該數據是一個常量,或者在運行時被初始化的值,可是不但願被改變;習慣上,將既是static又是final的域用大寫表示,並使用下劃線來分割每一個單詞;java容許生成空白final,即在指定final時並未直接初始化,可是空白final必須確保在使用前初始化;
當final用於參數時,表示在方法中沒法更改該參數引用的對象;
當final用於方法時,表示該方法別鎖定,不能在繼承中重載;類中全部的private方法都隱式地被添加final關鍵詞;
當final用於類時,表示該類不可被繼承;