Java編程思想讀書筆記
代理很有意思,(我們姑且使用導出類和基類這樣的字眼,但要清楚我們不是在討論繼承里面的關鍵詞)在導出類里保存一個基類的對象,然后用自己的方法對該基類的種種方法進行包裝。
如何決定使用哪種方法復用類呢?is-a就繼承,has-a就用組合。而且,組合比繼承總體上使用更廣泛、代價更小。
向上轉型
這個就牛逼了,第八章,第九章,第十章都與此密切相關。看完本書之后印象最深的就是向上轉型了。
使用final的原因有很多種,一定要弄清楚為什么使用final,是由于設計還是效率。
final作用于數據的時候:final作用在基本對象比如int上,該值就成為不可改變的,一旦被初始化就無法再被更改,但是作用在普通的對象引用的時候,final使引用恒定不變,但是引用指向的對象是可變的。編譯器需要我們確保final對象一定要被初始化,我們可以通過在構造器中初始化他們,以達到相對自由的效果(稱為空白final,我認為這個名字容易讓人誤解)。java允許在參數列表中以聲明的方式將參數指明為final,這一特性主要用來向匿名內部類傳遞數據(這很重要)。
final作用于方法的時候,說明作者想保持該方法在繼承的過程中不被改變,并且不被覆蓋。同時,被final修飾的方法會被關閉“動態綁定”,這樣編譯器就會為final方法調用生成“有限”有效的代碼。之所以說有限,是因為隨著編譯器的牛逼,它生成的代碼越來越有效。
final作用于類的時候,即是作者聲明對該類的設計不允許任何繼承。
學習得更深入一些,可能對以下事實感到有興趣:java中所有的事物都是對象,每個類的編譯代碼都存在于電腦中的文件夾里(文件夾的層次根據反轉域名得到),該文件只有在需要使用程序代碼時才被加載。具體的說,就是“類在其任何static成員函數(包括構造函數)被訪問時加載”。第八章 多態
多態的重要基本原理就是向上轉型:繼承允許將對象視為它自己本身的類型或其基類型加以處處理。
將一個方法調用和一個方法主題關聯起來稱為綁定,java中所有的方法都是后期綁定(除了static方法和final方法),所以我們可以編寫只與基類打交道的程序代碼,并且這些代碼對所有的導出類都可以正確運行。
(為什么static不動態綁定:因為static方法的主要用法就是用類名.方法名這樣的方式來調用,不存在“發送消息給某個對象,讓對象判斷自己怎么做”這樣的情況。
為什么final不動態綁定:這是早期final的一種用法,由程序員指定某方法為final,意味著程序員明了動態綁定的機制,并且聲明該方法不需要動態綁定,這樣可以獲得更好的性能。這種用法已經很少使用了。)
初始化的時候,導出類的構造函數會自動調用基類的默認構造函數,此過程一直遞歸到最基本的基類。如果需要調用有參數的構造函數就需要手動執行。反過來,如果需要進行清理工作(大部分時候我們都不需要),務必手動執行基類的清理工作先。比如繼承鏈的每個類都實現dispose()方法,那么執行某個類的清理工作的時候,需要手動調用super.dispose()。不過此種情況下,務必在執行super.dispose()之前釋放成員對象,清理順序與執行順序是相反的。
此外,構造器方面有更加復雜的調用機制,我們不用理它,只需要知道一條有效的準則“用盡可能簡單的方法使對象進入正常狀態,如果可以的話避免調用其它方法”。
java編譯器能夠允許向上多態,就是因為java的機制能保存對象的類型信息,即rtti,正因為這種機制,java編譯器也允許向下轉型,以獲得擴展類的“擴展出”的方法。(另,擴展類“擴展”了方法的這種繼承不是“純繼承”,這樣做好不好?用戶自己度量)。向下轉型失敗的話會拋出一個classcastexception。
雖然這一章都是在講多態,但是多態并不總是解決問題最好的方案,它有可能使事情不必要地復雜起來,我們應該總是優先考慮更加靈活的組合。
第九章 接口
一種專門提供“接口”的類叫抽象類,若含有至少一個abstract方法,該類就必須被聲明為abstract的。抽象方法沒有方法體,派生類必須實現它,否則派生類也必須被生命為抽象的。
interface關鍵詞使抽象的概念更進了一步:1.這個“類”完全抽象。2.一個類可以向上轉型為多種interface。要讓一個類遵循某個特定接口,需要使用implement關鍵字。
在這一章中出現了“策略設計模式”這個詞。創建一個能夠根據所傳遞的參數對象的不同而具有不同行為的方法,被稱為策略設計模式。
策略設計模式跟適配器設計模式聯合使用可以提供非常強大的功能,比如我們遇到了無法更改的類(別人編寫的),想要它滿足我們的接口然后放到設計模式里面去(當然滿足了接口之后的用法就不止如此了),就可以編寫一個適配器,包裝該類同時產生我所需要的接口。