名稱屏蔽:如果java的基類擁有某個已被多次重載的方法名稱,那么在導出類中重新定義該方法名稱并不會屏蔽其在基類中的任何版本(這一點于C++不同)。因此,無論是在該層或者它的基類中對方法進行定義,重載機制都可以正常工作。這句話的意思是指:如果基類有方法 void method() String method(int i),那么在導出類中定義 int method(char a) 并不會吧基類的方法給屏蔽,基類的重載方法是可以用的。導出類同樣可以重載。
類的復用有兩種方法:組合(composition)和繼承
組合技術通常用于想在新類中使用現有類的功能而非它的接口這種情形,一般在新類中嵌入一個現有類的private對象。但有時,允許類的用戶訪問新類中的組合部分是極具意義的。如果成員對象自身都隱藏了具體實現,那么將它聲明為public也是安全的。
組合一般是將現有類型作為新類型底層實現的一部分來加以復用,而繼承復用的是接口,由于導出類具有基類的接口,所以它可以向上轉型至基類。
向上轉型
新類是現有類的一種類型。
向上轉型中子類將能看到父類被覆蓋字段
在子類繼承父類之后,如果子類與父類有同名的字段和方法,那么子類中的子段會代替或隱藏父類的子段,說明子類字段覆蓋了超類字段,但可以通過super關 鍵字去訪問超類字段。但是,在我們將子類對象向超類轉型的時候就會發生這個奇怪的現象,子類對象居然可以看到父類曾經被覆蓋掉的字段!
一定要注意:當把子類轉換成超類時,子類可以見到或訪問被隱藏的同名變量。Java允許名字重復的原因是,允許將來把新的字段加到超類中,而不影響已經使用了該名字的現有子類,子類將會繼續使用自己的字段副本。除非讓子類以超類對象的形式出現,方法可以覆蓋,但是字段不能被覆蓋。注意:最好不要隱藏超類中的字段名。
所以我們在進行向上轉型的時候一定要注意:不要訪問子類中那些“覆蓋”掉父類的字段(它并沒有真正覆蓋掉,在向上轉型的時候就可以訪問的到),要么將子類字段改名(在你知道父類代碼的情況下),要么通過方法來訪問字類字段(方法即使同名也肯定能覆蓋掉)。
在向上轉型的過程中,類接口中唯一可能發生的事情是丟失方法,而不是獲取它們。
是否需要從新類向基類進行向上轉型,如果必須向上轉型,則繼承是必要的。
final數據
1. 它可以是一個永不改變的“編譯期常量(compile-time constant)”。
2. 它可以是一個在運行期被初始化的值,而你不希望它被改變。
在編譯期常量的情況下,編譯器可以將該常量值帶入任何可能用到它的計算式中。就是說,可以在編譯期執行計算式,減輕了一些運行期的負擔。這類常量必須是基本類型。
一個既是static又是final的域只占有一份不能改變的存儲空間。
對于原始類型,final使數值恒定不變,而用于對象引用,final使引用恒定不變。一旦引用被初始化指向一個對象,就無法對它進行改變以指向另一個對象。然而,對象其自身卻是可以被修改的,Java并未提供使任何對象恒定不變的途徑。
Java允許生成空白final(Blank final),所謂空白final是指被聲明為final但又未給定初值的數據成員。無論什么情況,編譯器都確保空白 final在使用前必須被初始化。但是,空白final在關鍵字final的使用上提供了更大的靈活性,為此,一個類中的final數據成員就可以實現依對象而有所不同,卻又保持其恒定不變的特性。
Java允許你以在參數列表中以聲明的方式將參數指明為final。這意味著你無法在方法中更改參數引用所指向的對象。你可以讀參數,卻無法修改參數。
使用final方法的原因有兩個。第一個原因是把方法鎖定,以預防任何繼承類修改它的意義。這是出于設計的考慮:你想要確保在繼承中方法行為保持不變,并且不會被重載。
使用final方法的第二個原因是效率。如果你將一個方法指明為final,就是同意編譯器將針對該方法的所有調用都轉為內嵌(inline)調用。C++中的內聯函數,空間換時間
類中所有的private方法都被隱含是final的。由于你無法取用private方法,所以你也無法重載之。如果你試圖重載一個private方法(隱含是final的),看起來是奏效的,而且編譯器也不會給出錯誤信息。覆蓋只有在某方法是基類的接口的一部分時才會出現。如果某方法是private,它就不是基類的接口的一部分。
當你將某個類的整體定義為final時(通過將關鍵字final置于它的定義之前),你就聲明了你不打算繼承該類,而且也不允許別人這樣做。Final類禁止繼承,所以final類中所有的方法都隱式指定為final。
每個類的編譯代碼都存在于它自己的獨立的文件中。該文件只在需要使用程序代碼時才會被加載。一般來說,你可以說:“類的代碼在初次使用時才加載。”這通常是指知道類的第一個對象被構建時才發生加載,但是當訪問static數據成員或是static方法時,也會發生加載。
初次使用之處也是靜態初始化(static初始化)發生之處。所有的static對象和static代碼段都會在加載時依程序中的順序(即,你定義類時的書寫順序)依次初始化。當然,static只會被初始化一次。
用final修飾的成員變量表示常量,值一旦給定就無法改變!
final修飾的變量有三種:靜態變量、實例變量和局部變量,分別表示三種類型的常量。
從下面的例子中可以看出,一旦給final變量初值后,值就不能再改變了。
另外,final變量定義的時候,可以先聲明,而不給初值,這中變量也稱為final空白,無論什么情況,編譯器都確保空白final在使用之前必須被初
始化。但是,final空白在final關鍵字final的使用上提供了更大的靈活性,為此,一個類中的final
多態通過分離“做什么”和“怎么做”,從另一個角度將接口和實現分離開來。
“封裝”通過合并特征和行為來創建新的數據類型。“實現隱藏”則通過將細節“私有化”把接口和實現分離開來。多態的作用則是消除類型之間的耦合關系。
多態方法調用允許一種類型表現出與其他相識類型之間的區別,只要他們都是從同以基類導出而來的。這種區別是根據方法行為的不同而表現出來的,雖然這些方法都可以通過同一個基類來調用。
向上轉型可能會縮小接口,但不會比基類接口更窄。
前期綁定:若在程序執行前進行綁定(如果有的話,由編譯器和鏈接程序實現)后期綁定:在運行時根據對象的類型進行綁定。也稱動態綁定或運行時綁定
c語言都是前期綁定,java除了static方法和final方法外,其他所有的方法都是后期綁定,final可以有效地"關閉”動態綁定。
基類為自它那里繼承而來的所有導出類建立一個公用接口,導出類通過覆蓋這些定義,來為每種特殊類型提供單獨的行為。
從通用的基類繼承出的新的數據類型,從而新添一些新的功能,而那些操縱基類的接口的方法不需要任何改動就可以運用于新類。這正是“可擴展性”的程序的一般特征。
多態,將改變的事物與未變的事務分離開來。
只有非private方法才可以被覆蓋;但是還需要密切注意覆蓋private方法的現象,這時編譯器不會報錯,但是也不會按照我們所期望的來指向。
如果一個類包含一個或多個抽象方法該類必須被限定為抽象的。也可以創建一個沒有任何抽象方法的抽象類,僅是為了組織產生這個類的任何對象。
如果想從一個抽象類繼承,并想創建該新類的對象,那么就必須為基類中的所有的抽象方法提供方法定義。如果不這樣做,那么導出類便也是抽象類,且編譯器將強制我們用abstract關鍵字來限定這個類。
對象調用構造器的順序:
1.調用基類構造器。這個步驟會不斷地反復遞歸下去,首先是構造這種層次結構的根,后是下一層導出類,等到那個,知道最低層的導出類。
2.按聲明順序調用成員的初始化方法
3.調用導出類構造器的主體
清理的時候應該首先對其導出類進行清理,然后才是基類。這是因為導出類的清理可能會調用基類中的某些方法,所以需要使基類中的構件仍起作用而不應該過早地銷毀它們。
初始化實際的過程是:
1. 在其他任何事物發生之前,將分配給對象的存儲空間初始化成二進制的零
2. 按前面所述調用基類構造器
3. 按聲明的順序調用成員的差距是花方法
4. 調用導出類的構造器主體
這樣做有一個優點,那就是所有東西都至少初始化成零(或者某些特殊數據類型中與:零等價的值),而不是僅僅留作垃圾。其中包含通過“組合”而嵌入一個類內 部的對象引用,其值是null。所以如果忘記為該引用進行初始化,就會在運行時出現異常。查看輸出結果時,會發現其他所有的東西的值,都是會是零,這通常也 正是方法問題的證據。
編寫構造器時有一條準則:用盡可能簡單的方法使對象進入正常狀態;如果可以的,避免調用其他的方法。在構造器內唯一能夠安全調用的方法是基類中的final方法(也適合于private)。這些方法不能被覆蓋。
導出類中接口的擴展部分不能被基類訪問,因此,向上轉型,不能調用新方法。
向上轉型會丟失具體類型信息,但向上轉型是安全的。
在java中,所有的類型轉換都會得到檢查。所以即使我們知識進行一次普通的加括號形式的類型轉型,在進入運行期仍會對其檢查,以便保證它的確是我們希望的那種類型。否則,會返回一個ClassCastException異常。運行時類型識別RTTI。