開頭先回憶一下,物件導向的三大特徵:封裝(資料抽象)、繼承、多型。為什麼多型排在最後一位,因為它是以前面兩個為前提的,尤其是繼承。
多型本質在於同一種行為的多樣化表達(這句話不禁讓我想起了基因的多樣性表達,這是現實世界物種多型的原因)。
對於某一種行為而言,它的多樣性體現在兩種可能:
1.行為主體相同,行為受體不同——同樣是待客,為什麼他對別人溫柔對你兇?
2.行為受體相同,行為主體不同——同樣是吃肉,人是煮熟吃,動物生吃。
這是我們在生活中的例子,現在我們遷移到程式設計中的多型!
我們是不是可以把乙個方法稱為一種行為,他的呼叫者我們稱為「行為主體」 ,他的引數我們稱為」行為受體」呢,而把函式體看作是行為的具體內容?程式設計中,多型分為 編譯時多型 和 執行時多型,也稱為前期繫結和動態繫結。
編譯時多型:程式設計中的體現是方法過載,呼叫者是明確的,呼叫方法有多種,我們根據引數來確定呼叫哪個方法,從而體現多樣性。
執行時多型:根源於繼承之後的方法重寫,多個子類都繼承了相同父類,並且都對父類中某個普通方法進行了重寫,從而體現多樣性。
首先,先建立繼承關係如下:
能實現轉型,是執行時多型的必要條件之一。
編譯的機制:
根據你引用指定的型別去搜尋你的方法是否存在,如果該引用型別中不存在呼叫方法,報錯。
執行時機制:
執行時,是根據引用所指的具體物件型別來呼叫方法。
當我們將父類中的study()方法注釋:
執行時:
從機器級角度分析這個問題:
編譯時根據物件引用確定該方法的符號引用名稱,執行時根據物件引用指向的物件進行符號引用的重定位。
如果你是乙個大學生,那麼你肯定也是一名學生。
我們對你所屬的範圍進行了一次周延擴大,這就是一次向上轉型。
用處:
1.提高了程式的擴充性,不需要寫一些重複的**。
2.增加**簡潔性,可閱讀性。
假設我們有乙個老師,他既教高中生,也教大學生,不同學生上課方式不同,正常那我們不是要進行方法過載為每個學生量身定製乙個方法嗎?但是我們可以讓他們自適應:
結果:
向上轉型高階分析:
如果方法呼叫者和方法引數都是具有繼承關係的型別,這個向上轉型是怎麼轉的呢?
觀查測試樣例:
輸出:
a and b
當我們將a類中的show(b)注釋掉:
輸出:
b and a
規律總結:
先是呼叫者由下到上向上轉型查詢對應方法; 若沒找到,每次將呼叫引數向上轉型一次,再尋找對應方法。你是乙個學生,但不一定是大學生。向下轉型,一定要注意型別的匹配。
為什麼又會有向下轉型?向上轉型的弊端在於被呼叫方法受到侷限,而當你又想呼叫子類獨有的方法,你就必須用 向下轉型 轉回去。
所以向下轉型一定是先有向上轉型作鋪墊的。
但是,這邊注意一點,你物件是什麼型別,你轉回去也應該是什麼型別。
人->動物->豬 ×根據我們之前總結的規律,看看你的答案是否正確吧:人->動物->人 √
編譯沒有報錯,但執行一定丟擲轉型異常。
正確做法:
class a
public string show(a obj)
}class b extends a
public string show(a obj)
}class c extends b
class d extends b
public class demo
}輸出:
1--a and a
2--a and a
3--a and d
4--b and a
5--b and a
6--a and d
7--b and b
8--b and b
9--a and d
物件導向之多型(向上轉型與向下轉型)
什麼是多型 同乙個行為具有多個不同表現形式或形態的能力就是多型。多型一般分為兩種 重寫式多型和過載式多型。過載式多型,也叫編譯時多型。也就是說這種多型再編譯時已經確定好了。過載大家都知道,方法名相同而引數列表不同的一組方法就是過載。在呼叫這種過載的方法時,通過傳入不同的引數最後得到不同的結果。重寫式...
多型向上向下轉型!
public abstract class animal public class cat extends animal void catchmouse 特有方法!public class dog extends animal void watchhouse 其實前面已經有所涉及,具體來說 以動物為...
多型,向上向下轉型
多型的前提 繼承 物件的多型 乙個物件擁有多種形態,例如小明有學生形態,有人類形態 中體現多型性 其實就是一句話,父類引用指向子類物件 person p new student 上句是向上轉型,一旦向上轉型為父類,就無法呼叫子類原本特有的內容 public class person public c...