java多態的內存圖解

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。android

圖解Java多態內存分配以及多態中成員方法的特色
spa

Person worker = new Worker(); 子類實例對象地址賦值給父類類型引用變量。多態的體現。.net


多態中成員方法的特色分析:對象


【子類有,父類沒有】編譯失敗!!!
worker.startWork(); 爲何編譯不經過呢?提示:找不到符號。
由於引用變量worker是Person類型,在Person類的方法表中查找方法startWork(),找獲得嗎?找不到,更別提常量池解析了。編譯失敗。


【子類有,父類有,重寫,非靜態】調用子類!!!
worker.say(); 子類重寫父類方法,被重寫的方法在子類跟父類的方法表中索引相同。
調用的時候,在父類類型的方法表中查找say方法的索引,而後把索引存到PolDemo類的常量表中(常量池解析,就是用Person類方法表中的索引項來代替常量池中的符號引用)。
由於索引相同,直接拿常量表中say方法的索引去子類方法表中調用say()方法。 因此,此時調用的是被子類重寫的方法。見圖中的內存分配。


【子類有,父類有,靜態】調用當前引用類型變量類型中的方法。
由於靜態是屬於類的,由實例共享,因此只看當前引用變量所屬的類中的靜態方法。


多態中(父類引用指向子類對象)成員方法(非靜態)有如下特色:
編譯期根據引用類型變量所屬的類型方法表中是否有調用的方法,沒有編譯失敗。
運行期根據在堆中建立對象的實際類型找到對應的方法表,從中肯定具體的方法在內存中的位置。


堆中實例對象:子類包含父類,子類對父類說:你的就是個人,個人仍是個人。


多態中成員變量的特色分析:
不管編譯期仍是運行期,都只參考引用類型變量所屬的類中是否有對象的成員變量。


小的總結:
再來看這條語句:Person worker = new Worker(): 多態,父類引用指向子類對象。
跟這句代碼的做用是同樣的,Worker w = new Worker(); Person worker = w; 就是子類的引用傳給父類類型的引用。向上轉型,都指向一個實例對象(子類)。
1:爲何能夠將子類實例對象的引用傳給父類類型引用呢? 
答:多態的體現,鴿子是鳥類,鸚鵡是鳥類,喜鵲是鳥類,它們都是鳥類,這就是鳥類的多種表現形態(多態),
它們有鳥類的基本特徵與行爲,而且還有本身特有的行爲,那就會把鳥類的基本特徵與行爲繼承過來給本身。extends關鍵字聲明瞭他們的關係。
程序中這句話 鳥類 xx鳥 = new 鴿子();就建立了一個鳥類的引用,它是鴿子。
類的概念是抽象的,因此它就僅僅是個引用,只有引用到實例對象,它才真正實現了本身。


2:父與子的關係會怎樣呢?
因爲Worker類繼承自Person類,因此會先加載Person類並初始化成員變量在Worker類實例對象中。這就是子類繼承過來的成員變量。
若是子類中定義了與父類相同的成員變量,變量不會存在重寫,子類實例對象中會有兩份相同名稱的實例變量,調用時,父類的會被隱藏。
若是想調用父類被隱藏的成員變量,那就要使用super關鍵字。
一樣,子類會繼承父類的成員方法做爲本身的成員方法,若是子類定義了與父類相同的成員方法(重寫),多態中會調用子類本身的成員方法。


3:多態,又有什麼好處呢?跟這樣寫(Worker worker = new Worker();)有什麼區別,不同繼承父類的屬性方法嗎?
首先明確: Worker worker = new Worker();這樣寫僅僅是繼承關係。不存在多態特性。
Person worker = new Worker(); 這樣寫就展現了多態的關係,鴿子是鳥類的一種表現形態。
有啥好處?一句話歸納:提升了程序的擴展性,表如今什麼地方呢?好比:
如今有個工廠,能解析鳥類的語言,鴿子是鳥類吧?Ok,那建一個工廠,讓鴿子說。
public static void doWork(Dove dove) {
String sound = dove.say(); // ... 拿到鴿子說的話
}
鸚鵡是鳥類吧?Ok,那建一個工廠,讓鸚鵡說。
public static void doWork(Parrot parrot) {
String sound = parrot.say(); // ... 拿到鸚鵡說的話
}
若是還有一千個鳥類要說話,那我豈不得建一千座工廠?。。。累不累?那既然都是鳥類,我建一個鳥類的工廠不就好了嘛?
public static void doWork(Bird bird) {
String sound = bird.say(); // ... 拿到xx鳥說的話。。。
}
這時候,不管你什麼鳥進來,我都讓你說話,並且說得都是你本身的話,由於你繼承我並重寫了你的功能。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Worker w = (Worker)worker; // 向下轉型。目的,爲了調用子類非繼承父類、本身特有的方法。
由於多態有個弊端,只能使用父類的引用訪問父類的成員。因此向下轉型是爲了訪問子類本身的成員。
首先,worker引用指向的實例對象原本就是子類類型的。因此賦值給子類類型引用變量很是能夠。
而後如今用子類類型的引用就能夠訪問本身的成員方法了啦啦啦。
blog

相關文章
相關標籤/搜索