Java對象類型轉(zhuǎn)換的四個經(jīng)驗
一、向上轉(zhuǎn)型與向下轉(zhuǎn)型。
對象類型的轉(zhuǎn)換在Java語言平臺中經(jīng)常遇到,主要包括向上轉(zhuǎn)型與向下轉(zhuǎn)型操作。程序開發(fā)人員需要熟練掌握這兩個轉(zhuǎn)型的方法以及其中容易出錯的地方。如何來了解這兩個轉(zhuǎn)型的區(qū)別呢?筆者認為,以一個現(xiàn)實的例子作為比喻,可能會更加的容易理解。
如現(xiàn)在有動物、鳥類、燕子三個名詞,他們之間有什么關(guān)系呢?通常我們都會說,燕子是特殊的鳥類,或者說燕子是鳥類的一種。為此,從對象的定義來看,鳥類就是一個父類,而燕子就是一個子類。或者說,燕子對象就是一個鳥類對象。筆者這里要強調(diào)的一點就是,由于燕子是鳥類的一個對象,所以鳥類所具有的特性燕子全部具有。而燕子所具有的特性(如遷徙)則鳥類不一定都具有。在這個例子中,燕子也是一種鳥類。為此可以將燕子的對象堪稱是一個鳥類的對象。這種方法在Java語言環(huán)境中就叫做“向上轉(zhuǎn)型”。從這個例子中可以看出,向上轉(zhuǎn)型是一個從較抽象類型的類(鳥類)向比較具體的類(燕子)過度。由于具體類(燕子)具有抽象類(鳥類)的全部特性,所以在這個轉(zhuǎn)換過程中是不會有問題的。這就好像一個邏輯判斷題說燕子是鳥類的一種,其具有鳥類的全部特性。這個命題至少到現(xiàn)在為止是完全正確的。
但是,在實際工作中,我們還經(jīng)常會遇到向下轉(zhuǎn)型的情況。也就是說從一個抽象類中(鳥類)引用具體類(燕子)中的對象。也就是說,我們可以說燕子是鳥類的一種。但是現(xiàn)在反過來,如果說鳥類就是燕子,那顯然就是以偏概全了,因為燕子并不具有其他鳥類的特性。如鴿子的特性燕子就沒有。所以,在應(yīng)用程序開發(fā)中,如果將父類對象賦值給子類的對象,就可能有問題。如果硬要這么做的話,則很有可能發(fā)生編譯器錯誤。因為父類對象并不一定是子類的實例。這是什么意思呢?即所說的鳥類(父類對象)并不一定是子類對象(燕子)。因為鳥類對象還有可能是鴿子、白鷺等等。所以,如果將父類對象給子類對象的話,那么就會出現(xiàn)問題。
二、如何實現(xiàn)向下轉(zhuǎn)型?
由于向上轉(zhuǎn)型一般都是安全的,即將一個子類對象直接賦值給父類對象,一般被認為是安全的,如燕子是鳥類在哪里都是成立的。所以在向下轉(zhuǎn)型時不需要采用其他的關(guān)鍵字,我們常常把向下轉(zhuǎn)換叫做隱式轉(zhuǎn)換。但是在這里向上轉(zhuǎn)換是一種不安全的轉(zhuǎn)換方式,如說鳥類就是燕子,這種說法無論在哪里都說不過去。為此默認情況下,進行向下轉(zhuǎn)型時,往往會發(fā)生編譯器錯誤。
一般情況下,越是具體的對象所具有的特性越多。如燕子的特性就比鳥類的特性多的多。而越抽象的對象反而具有的特性越少,因為其只具有一些抽象對象的共性特征。在進行向下轉(zhuǎn)型操作時,將特性范圍小的對象轉(zhuǎn)換為特性范圍大的對象肯定會出現(xiàn)問題。為此在向下轉(zhuǎn)型時,必須確保轉(zhuǎn)換后不會出現(xiàn)問題,即具體對象的特性在抽象對象中也全部具備,只有如此才能夠進行轉(zhuǎn)換。而且即使?jié)M足這個條件,編譯器也不不能夠進行隱式轉(zhuǎn)換。而是需要采用關(guān)鍵字進行強制轉(zhuǎn)換。如子類對象名字=(子類名)父類對象名字。如果上面這個語法,就可以實現(xiàn)對象類型的強制轉(zhuǎn)換。
筆者在此強調(diào)一遍,在進行向下轉(zhuǎn)型時一定要進行強制轉(zhuǎn)換。即通過子類對象名字=(子類名)父類對象名字進行賦值,而不能夠向向上轉(zhuǎn)型那樣進行隱式轉(zhuǎn)換。
三、確保向下轉(zhuǎn)型的準確性。
從以上分析中可以看出,向下轉(zhuǎn)型往往被認為是不安全的。當(dāng)在程序中執(zhí)行向下轉(zhuǎn)型操作的時候,如果父類對象不是子類對象的實例,就會發(fā)生編譯器錯誤。所以在執(zhí)行向下轉(zhuǎn)型之前要先作一件事情,就是判斷父類對象是否為子類對象的實例。也就是說,先要想一想,燕子就是鳥類這個命題是否成立(在某些特定的情況下這個偽命題可能會成立,如燕子的特性與鳥類的特性完全一致)。只有如此,向下轉(zhuǎn)型才不會出現(xiàn)問題。在進行向下轉(zhuǎn)型操作時,將特性范圍小的對象轉(zhuǎn)換為特性范圍大的對象肯定會出現(xiàn)問題。但是,如果兩個轉(zhuǎn)換的對象特性范圍一樣大的話,可那么就不會有問題了。
在應(yīng)用程序開發(fā)中,往往通過操作符instanceof來完成這個判斷。即可以利用這個操作符來判斷是否一個雷實現(xiàn)了某個接口,也可以用來判斷一個實例對象是否屬于一個類。這個操作符的基本格式為:A(某個類的對象引用) instanceo(操作符號) B (某個類的名稱)。這個操作符***返回的是一個布爾值。如果是false的話,則說明A對象不是類B的實例對象。相反,如果返回的值是true的話,則說明對象A是類B的實例對象。
四、向下轉(zhuǎn)型的注意事項。
在進行向下轉(zhuǎn)型時,需要注意以下幾方面的內(nèi)容:
一是要慎用向下轉(zhuǎn)型。由于向下轉(zhuǎn)型容易出問題,為此不到萬不得已的時候,***不用使用向下轉(zhuǎn)型。條條道路通羅馬,如果在編程之前,合理規(guī)劃類,往往可以避免向下轉(zhuǎn)型的發(fā)生。只有其他路走不通的情況下,才考慮通過向下轉(zhuǎn)型的技術(shù)來解決問題。
二是在進行向下轉(zhuǎn)型的時候,需要做兩件事情。一是一定要使用instanceof操作符來判斷轉(zhuǎn)型的合法性,即判斷父類對象是否為子類對象的實例。這就好像在編寫四則運算時,要判斷除數(shù)不為零一樣。這是必須要做的。也是程序員必須要養(yǎng)成的一個習(xí)慣。在進行向下轉(zhuǎn)型時,就自然而然會想到需要進行這個判斷。只有如此,應(yīng)用程序的錯誤才能夠降低。而且還能夠滿足不同的需求。二是需要注意向上轉(zhuǎn)型與向下轉(zhuǎn)型的區(qū)別。一般情況下,向上轉(zhuǎn)型往往被認為是安全的,所以在Java語言平臺中向上轉(zhuǎn)型采用的是隱式轉(zhuǎn)型。而向下轉(zhuǎn)型由于特性范圍大小的不同,為此往往被認為是不安全的。故系統(tǒng)默認情況下進行向下轉(zhuǎn)型時必須采用強制轉(zhuǎn)型的方式。如果不采用強制轉(zhuǎn)型,則即使?jié)M足向下轉(zhuǎn)型的條件,其也會發(fā)生編譯器錯誤。所以需要切記,向下轉(zhuǎn)型必須要采用強制轉(zhuǎn)型。
三是需要做好備注等注釋工作。由于像向下轉(zhuǎn)型等操作是容易出現(xiàn)問題的地方。為此在進行類似的操作時,***在行注釋或者塊注釋中能夠進行說明。這對于后續(xù)的維護與代碼的升級是很有幫助的。好記性不如爛筆頭。如果沒有做好相關(guān)注釋的話,這次可能沒有問題,但是下次再代碼升級或者其他原因需要調(diào)整或者重寫原有的代碼時,就可能會因為疏忽而導(dǎo)致轉(zhuǎn)型的失敗。
***筆者再次提醒各位程序員,向上轉(zhuǎn)型大家可以放心大膽的用。但是在使用向下轉(zhuǎn)型技術(shù)時,大家要慎重,要按部就班(先判斷后使用)的進行操作。
【編輯推薦】