Java基礎00-多态191. 多态
多态

代碼示例:
動物類:
貓類:
多态的前提有繼承/實作關系,是以貓類要繼承動物類。
多态的前提要有方法重寫,是以要重寫父類的eat()方法。
實作類:
要有父類引用指向子類對象
這樣就滿足了多态的前提,這樣的現象就稱之為多态。
通路成員變量的特點:
直接通過對象名稱通路成員變量:看等号左邊是誰,優先用誰,沒有則向上找。
間接通過成員方法通路成員變量:看該方法屬于誰,優先用誰,沒有則向上找。
通路成員方法的特點:
看new的是誰,就優先用誰,沒有則向上找。
貓類:
繼承了動物類,并重寫的父類的eat()方法
測試類:
a.age調用可以使用,但是a.weight調用不可以使用,
因為,雖熱記憶體中指向的是子類new Cat(),但是外界看到的是Animal a,通過多态的方式在通路成員變量的時候它的編譯要看左邊(父類),要看左邊(父類)中有沒有,有就可以調用,沒有就不可以調用。
接下來運作測試類:
通過多态的形式,去通路成員變量,其實是通路左邊(父類)中的,是以,通過多态的形式,通路成員變量,它的編譯看右邊,運作也看右邊。
接下來調用成員方法:
調用a.eat()方法成功,a.playGame()失敗,
可見調用成員方法和變量是一樣的,編譯也要看左邊(父類),右邊有可以通過,沒有就不可以。
運作測試類:
運作的是重寫後的方法,由此可見
通過多态的方式,調用成員變方法看的是右邊(子類),運作看右邊
類目錄:
貓類繼承了動物類并重寫了它的eat()方法。
動物操作類:
它的成員方法的形成類型是Cat。
運作測試類并調用操作類的方法:
運作:
ao.useAnimal©,解析:
調用ao(操作類)中的useAnimal成員方法,
useAnimal方法的形參類型是Cat(貓類),
是以将main方法中的Cat c(指向的就是new Cat())(貓類)放入形參中,此時的形參相當于:Cat c = new Cat();
c.eat()方法調用貓類的eat方法,
輸出“貓吃魚”。
再加一個狗類型:
和上面的一樣,先建立一個狗類,再在操作類中添加一個新的useAnimal方法這次的形參類型是狗類,調用的是狗類的eat方法。
這樣的方法明顯比較麻煩,如果要建立多個動物就要重複上面的每一個步驟,
是以我們運用多态。
修改操作類:
将useAnimal方法中的形參變為Animal(動物類),
因為不管貓還是狗,它們都繼承Animal(動物類),
是以我們完全可以将Animal(動物類)作為形參。
接着運作測試類:
運作結果:
運作結果和以前一樣,解析:
以Cat(貓)為例,
ao.useAnimal©,
調用ao(AnimalOperator)的useAnimal方法,
useAnimal方法的形參類型是Animal(動物類),Cat(貓)類的父類也是Animal(動物類),
是以完全可以将Cat c(指向new Cat())指派給Animal(動物類),這樣就變成了,Animal a = new Cat();
這樣就形成了多态,多态調用成員方法時,編譯看左邊,運作看右邊,
是以我們就是輸出“貓吃魚”
這樣利用多态就可以省去多個步驟,建立一個useAnimal方法即可。
但是這樣不可以調用子類的特有方法,因為編譯看左邊(父類)。
向上轉型:
父類引用指向子類對象,子類對象指派給父類引用
但是通過向上轉型的方法,通路不了子類特有的方法。
是以要用到向下轉型
父類引用a轉為子類對象Cat,指派給Cat
運作:
從main方法開始執行,加載到棧記憶體
Animal a加載到棧記憶體
在堆記憶體中new一片空間(001),Cat繼承了Animal,是以将位址001指派給Animal a。
這也叫向上轉型
多态中執行方法,編譯看左邊,執行看右邊,将Cat類加載到棧記憶體中,調用eat方法,輸出“貓吃魚”。
調用完畢後從棧記憶體消失
執行Cat c = (Cat) a;,将Cat c加載到棧記憶體中
a指向的是堆記憶體中的001,而001就是Cat,是以001完全可以指派給Cat
這就是向下轉型
c指向位址001(Cat),是以可以調用Cat中的方法。
執行a = new Dog();,先在堆記憶體中new一片空間002,Dog也繼承了Animal,是以也可以指派給a,這時a的位址值變了002。
執行a.eat():,調用方法執行看右邊,進入Dog類執行eat()方法,輸出“狗吃骨頭”。
方法執行結束從棧記憶體消失。
Cat cc = (Cat) a;,将Cat cc加載到棧記憶體,(Cat) a,a的位址值是002,002對應的是Dog方法。
雖然貓和狗都繼承自Animal但是兩者是沒有任何關系的,是以他們互相之間是不能進行轉換的。
是以這個地方是錯誤的,如果強制執行就會報錯,類型轉換異常。