柚子快報(bào)邀請碼778899分享:開發(fā)語言 Java——多態(tài)
柚子快報(bào)邀請碼778899分享:開發(fā)語言 Java——多態(tài)
1.多態(tài)概述
多態(tài)是面向?qū)ο笳Z言三大特征之一,多態(tài)是指對象的多種形態(tài),就是同類型的對象,表現(xiàn)出的不同形態(tài)。
多態(tài)的前提:有繼承關(guān)系,有父類引用指向子類對象,有方法重寫
多態(tài)的表現(xiàn)形式:父類類型 對象名稱=子類對象;
1.1多態(tài)的場景應(yīng)用
在一個(gè)球類信息管理系統(tǒng)當(dāng)中,我們要去寫一個(gè)方法查看各種各樣球的信息
是每一種球都寫一種方法查看信息呢?還是只寫一種方法去查看所有的球的信息好呢?
答案肯定是只寫一種
接下來簡單的實(shí)現(xiàn)一個(gè)球類信息查看的系統(tǒng)
class Ball{
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public void show(){
}
}
class pingpong extends Ball{
public void show(){
System.out.println("乒乓球的價(jià)格為"+getPrice()+"元");
}
}
class badminton extends Ball{
public void show(){
System.out.println("羽毛球的價(jià)格為"+getPrice()+"元");
}
}
class basketball extends Ball{
public void show(){
System.out.println("籃球的價(jià)格為"+getPrice()+"元");
}
}
class football extends Ball{
public void show(){
System.out.println("足球的價(jià)格為"+getPrice()+"元");
}
}
public class T2 {
public static void main(String[] args) {
Ball b1=new pingpong();
b1.setPrice(2);
show(b1);
Ball b2=new badminton();
b2.setPrice(4);
show(b2);
}
public static void show(Ball p){
p.show();
}
}
當(dāng)我們將乒乓球和羽毛球的對象賦值給父類的對象時(shí),將父類類型作為查看信息的方法的形參,用父類類型的變量調(diào)用show方法時(shí),會發(fā)現(xiàn)父類類型的變量會調(diào)用不同子類的show方法,這就是多態(tài)的一種應(yīng)用場景
2.多態(tài)調(diào)用成員的特點(diǎn)
1.變量調(diào)用:編譯看左邊,運(yùn)行也看左邊
2.方法調(diào)用:編譯看左邊,運(yùn)行看右邊
2.1變量調(diào)用
class Animal{
}
class Dog extends Animal{
String name;
}
public class T3 {
public static void main(String[] args) {
Animal ani=new Dog();
ani.name="張三";
}
}
編譯看左邊:javac編譯代碼的時(shí)候會看左邊的父類里面有沒有這個(gè)變量,如果有,則成功編譯,否則編譯失敗。上面代碼因?yàn)楦割惱锩鏇]有name這個(gè)變量,所以會編譯失敗
class Animal{
String name="動物";
}
class Dog extends Animal{
String name="狗";
}
public class T3 {
public static void main(String[] args) {
Animal ani=new Dog();
System.out.println(ani.name);
}
}
運(yùn)行也看左邊:我們分別給父類和子類的name賦不同值時(shí),在用ani調(diào)用name時(shí),輸出的結(jié)果是動物,也就是運(yùn)行時(shí)ani調(diào)用的是父類的name
2.2方法調(diào)用
class Animal{
}
class Dog extends Animal{
public void show(){
System.out.println("Dog的show");
}
}
public class T3 {
public static void main(String[] args) {
Animal ani=new Dog();
ani.show();
}
}
編譯看左邊:和變量調(diào)用一樣,ani調(diào)用show方法時(shí),父類里面有show,則編譯成功,沒有則編譯失敗
class Animal{
public void show(){
System.out.println("Animal的show");
}
}
class Dog extends Animal{
public void show(){
System.out.println("Dog的show");
}
}
public class T3 {
public static void main(String[] args) {
Animal ani=new Dog();
ani.show();
}
}
運(yùn)行看右邊:Animal和Dog類里面都有show方法時(shí),我們使用ani調(diào)用show方法時(shí),ani會調(diào)用子類Dog里面的show方法
2.3對方法調(diào)用和變量調(diào)用的理解
成員變量:
在子類的對象中,會把父類的成員變量繼承下來
當(dāng)我們Animal a=new Dog();時(shí),父類里面有一個(gè)name,子類里面也有一個(gè)name,這兩個(gè)name在對象里面都是存在的
之前我們用Dog dog=new Dog()創(chuàng)建一個(gè)對象時(shí),用dog調(diào)用name,dog是Dog類型,他會去Dog類里面尋找name,現(xiàn)在用Animal a=new Dog();創(chuàng)建a對象,a是Animal類型,a調(diào)用name,那么他就會去Animal里面去尋找name
成員方法:
當(dāng)我們運(yùn)用多態(tài)去調(diào)用方法時(shí),子類里面的方法其實(shí)是對父類方法的重寫,而子類繼承父類方法時(shí)繼承父類的虛方法表,當(dāng)子類對父類方法進(jìn)行重寫時(shí),會將父類方法在虛方法表中的虛方法覆蓋,從而在用ani.show時(shí),調(diào)用的是子類的方法
2.4多態(tài)調(diào)用成員的內(nèi)存圖解
?1.測試類的字節(jié)碼文件T3.class先加載到方法區(qū)當(dāng)中,java虛擬機(jī)會自動的將main方法加載進(jìn)棧
2.在main方法的第一行代碼,即用到了Animal類又用到了Dog類,在Java中,永遠(yuǎn)是先加載父類,再加載子類,Java中有一個(gè)所有類的祖宗類(object類),這里object沒太大關(guān)系,所以在圖中就不畫了,在方法區(qū)中先加載Animal.class,再加載Dog.class。
(在字節(jié)碼文件中會加載所有的成員變量和成員方法,在成員方法的下面會掛一個(gè)需方法表,子類的重寫方法會將繼承下來的虛方法表中父類show方法的虛方法覆蓋)
(子類會和父類有聯(lián)系,他會記錄父類字節(jié)碼文件的位置)
3.第一行代碼等號的左邊會在棧內(nèi)存里面開辟一個(gè)Animal類型,名為ani的空間,等號右邊,new關(guān)鍵字代表在堆內(nèi)存里面開辟了一個(gè)小空間,在對象里面,他會將這個(gè)空間分為兩部分,一部分用來存儲在父類繼承下來的成員信息,另一部分會存儲自己的成員信息,假設(shè)這塊堆內(nèi)存的地址值為1900,棧內(nèi)存里面ani的空間會存儲1900這個(gè)地址值,ani可以通過1900找到堆內(nèi)存里面的變量
4.第二行代碼sout(ani.name),這時(shí)就編譯看左邊,運(yùn)行也看左邊,看1900里面父類是否有name,有就編譯成功,否則失敗,ani是Animal類型的,他直接去父類里面調(diào)用name
5.第三行代碼,編譯看左邊,運(yùn)行看右邊,編譯時(shí)他會去看父類里面有沒有show,有則編譯成功,否則編譯失敗。在運(yùn)行時(shí)他會去子類里面找show方法,因?yàn)樽宇愔匦聦⑿璺椒ū碇械膕how方法覆蓋,所以調(diào)用的是子類的show方法
3.多態(tài)的優(yōu)勢和弊端
優(yōu)勢:
1.在多態(tài)形式下,右邊對象可以實(shí)現(xiàn)解耦合,便于擴(kuò)展和維護(hù)
舉例:
Animal a=new Dog();
a.eat;
當(dāng)我后面想要Cat的eat時(shí),只需將new Dog()改成new Cat(),就可完成業(yè)務(wù)邏輯的修改,無需將后續(xù)的代碼修改
2.定義方法的時(shí)候,使用父類類型作為參數(shù),可以接收所有的子類對象,體現(xiàn)多態(tài)的擴(kuò)展性和便利
弊端:
1.不能調(diào)用子類的特有方法
解決方案:強(qiáng)制轉(zhuǎn)換,將調(diào)用者變回子類類型,轉(zhuǎn)換時(shí)不能瞎轉(zhuǎn),即Animal dog=new Dog();不能將dog轉(zhuǎn)成Cat類型,瞎轉(zhuǎn)會報(bào)類型轉(zhuǎn)換異常
補(bǔ)充:instanceof關(guān)鍵字
instanceof關(guān)鍵字是判斷某一個(gè)對象是不是某個(gè)類型
格式:
對象名 instanceof 類名
如果這個(gè)對象的類型是后面那個(gè)類,那么整個(gè)結(jié)果是true 否則是false
柚子快報(bào)邀請碼778899分享:開發(fā)語言 Java——多態(tài)
相關(guān)閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。