java基礎學習總結——多態(tài)(動態(tài)綁定)

原文: java基礎學習總結——多態(tài)(動態(tài)綁定)

一、面向對象最核心的機制——動態(tài)綁定悲敷,也叫多態(tài)

image.png

1.1.通過下面的例子理解動態(tài)綁定屎暇,即多態(tài)

package javastudy.summary;

class Animal {
    /**
     * 聲明一個私有的成員變量name囚巴。
     */
    private String name;

    /**
     * 在Animal類自定義的構造方法
     * @param name
     */
    Animal(String name) {
        this.name = name;
    }

    /**
     * 在Animal類里面自定義一個方法enjoy
     */
    public void enjoy() {
        System.out.println("動物的叫聲……");
    }
}

/**
 * 子類Cat從父類Animal繼承下來您炉,Cat類擁有了Animal類所有的屬性和方法柒爵。
 * @author gacl
 *
 */
class Cat extends Animal {
    /**
     * 在子類Cat里面定義自己的私有成員變量
     */
    private String eyesColor;

    /**
     * 在子類Cat里面定義Cat類的構造方法
     * @param n
     * @param c
     */
    Cat(String n, String c) {
        /**
         * 在構造方法的實現(xiàn)里面首先使用super調用父類Animal的構造方法Animal(String name)。
         * 把子類對象里面的父類對象先造出來赚爵。
         */
        super(n);
        eyesColor = c;
    }

    /**
     * 子類Cat對從父類Animal繼承下來的enjoy方法不滿意棉胀,在這里重寫了enjoy方法法瑟。
     */
    public void enjoy() {
        System.out.println("我養(yǎng)的貓高興地叫了一聲……");
    }
}

/**
 * 子類Dog從父類Animal繼承下來,Dog類擁有了Animal類所有的屬性和方法唁奢。
 * @author gacl
 *
 */
class Dog extends Animal {
    /**
     * 在子類Dog里面定義自己的私有成員變量
     */
    private String furColor;

    /**
     * 在子類Dog里面定義Dog類的構造方法
     * @param n
     * @param c
     */
    Dog(String n, String c) {
        /**
         * 在構造方法的實現(xiàn)里面首先使用super調用父類Animal的構造方法Animal(String name)霎挟。
         * 把子類對象里面的父類對象先造出來。
         */
        super(n);
        furColor = c;
    }

    /**
     * 子類Dog對從父類Animal繼承下來的enjoy方法不滿意麻掸,在這里重寫了enjoy方法酥夭。
     */
    public void enjoy() {
        System.out.println("我養(yǎng)的狗高興地叫了一聲……");
    }
}

/**
 * 子類Bird從父類Animal繼承下來,Bird類擁有Animal類所有的屬性和方法
 * @author gacl
 *
 */
class Bird extends Animal {
    /**
     * 在子類Bird里面定義Bird類的構造方法
     */
    Bird() {
        /**
         * 在構造方法的實現(xiàn)里面首先使用super調用父類Animal的構造方法Animal(String name)脊奋。
         * 把子類對象里面的父類對象先造出來采郎。
         */
        super("bird");
    }

    /**
     * 子類Bird對從父類Animal繼承下來的enjoy方法不滿意,在這里重寫了enjoy方法狂魔。
     */
    public void enjoy() {
        System.out.println("我養(yǎng)的鳥高興地叫了一聲……");
    }
}

/**
 * 定義一個類Lady(女士)
 * @author gacl
 *
 */
class Lady {
    /**
     * 定義Lady類的私有成員變量name和pet
     */
    private String name;
    private Animal pet;

    /**
     * 在Lady類里面定義自己的構造方法Lady(),
     * 這個構造方法有兩個參數(shù)淫痰,分別為String類型的name和Animal類型的pet最楷,
     * 這里的第二個參數(shù)設置成Animal類型可以給我們的程序帶來最大的靈活性,
     * 因為作為養(yǎng)寵物來說待错,可以養(yǎng)貓籽孙,養(yǎng)狗,養(yǎng)鳥火俄,只要是你喜歡的都可以養(yǎng)犯建,
     * 因此把它設置為父類對象的引用最為靈活。
     * 因為這個Animal類型的參數(shù)是父類對象的引用類型瓜客,因此當我們傳參數(shù)的時候适瓦,
     * 可以把這個父類的子類對象傳過去,即傳Dog谱仪、Cat和Bird等都可以玻熙。
     * @param name
     * @param pet
     */
    Lady(String name, Animal pet) {
        this.name = name;
        this.pet = pet;
    }

    /**
     * 在Lady類里面自定義一個方法myPetEnjoy()
     * 方法體內是讓Lady對象養(yǎng)的寵物自己調用自己的enjoy()方法發(fā)出自己的叫聲。
     */
    public void myPetEnjoy() {
        pet.enjoy();
    }
}

public class TestPolymoph {
    public static void main(String args[]) {
        /**
         * 在堆內存里面new了一只藍貓對象出來疯攒,這個藍貓對象里面包含有一個父類對象Animal嗦随。
         */
        Cat c = new Cat("Catname", "blue");
        /**
         * 在堆內存里面new了一只黑狗對象出來,這個黑狗對象里面包含有一個父類對象Animal敬尺。
         */
        Dog d = new Dog("Dogname", "black");
        /**
         * 在堆內存里面new了一只小鳥對象出來枚尼,這個小鳥對象里面包含有一個父類對象Animal。
         */
        Bird b = new Bird();

        /**
         * 在堆內存里面new出來3個小姑娘砂吞,名字分別是l1署恍,l2,l3呜舒。
         * l1養(yǎng)了一只寵物是c(Cat)锭汛,l2養(yǎng)了一只寵物是d(Dog)笨奠,l3養(yǎng)了一只寵物是b(Bird)。
         * 注意:調用Lady類的構造方法時唤殴,傳遞過來的c般婆,d,b是當成Animal來傳遞的朵逝,
         * 因此使用c蔚袍,d,b這三個引用對象只能訪問父類Animal里面的enjoy()方法配名。
         */
        Lady l1 = new Lady("l1", c);
        Lady l2 = new Lady("l2", d);
        Lady l3 = new Lady("l3", b);
        /**
         * 這三個小姑娘都調用myPetEnjoy()方法使自己養(yǎng)的寵物高興地叫起來啤咽。
         */
        l1.myPetEnjoy();
        l2.myPetEnjoy();
        l3.myPetEnjoy();
    }
}

運行結果:

image.png

1.2.畫內存圖理解動態(tài)綁定(多態(tài))

首先從main方法的第一句話開始分析:

Cat c = new Cat("Catname","blue");

程序執(zhí)行到這里,椙觯空間里有一個變量c宇整,c里面裝著一系列的值,通過這些值可以找到位于堆內存里面new出來的Cat對象芋膘。因此c是Cat對象的一個引用鳞青,通過c可以看到這個Cat對象的全部。c指向new出來的Cat對象为朋。在new這個Cat對象的時候臂拓,調用了Cat對象的構造方法Cat(String n,String c),定義如下:

Cat(String n,String c){

  super(n);

  eyesColor=c;

 }

因此在構造子類對象時首先使用父類對象的引用super調用父類的構造方法Animal(String name),定義如下:

Animal(String name){

  this.name=name;

}

因此會把傳過來的字符串“Catname”傳遞給父類對象的name屬性习寸。當Cat(String n,String c)構造方法調用結束后胶惰,真真正正在堆內存里面new出了一只Cat,這只Cat里面包含有父類對象Animal霞溪,這個Animal對象有自己的屬性name孵滞,name屬性的值為調用父類構造方法時傳遞過來的字符串Catname。除此之外鸯匹,這只Cat還有自己的私有成員變量eyesColor剃斧,eyesColor屬性的屬性值為調用子類構造方法時傳遞過來的字符串blue。所以執(zhí)行完這句話以后忽你,內存中的布局是棧內存里面有一個引用c幼东,c指向堆內存里面new出來的一只Cat,而這只Cat對象里面又包含有父類對象Animal科雳,Animal對象有自己的屬性name根蟹,屬性值為Catname,Cat除了擁有從Animal類繼承下來的name屬性外糟秘,還擁有一個自己私有的屬性eyesColor简逮,屬性值為blue。這就是執(zhí)行完第一句話以后整個內存布局的情況如下圖所示:

image.png

接著看這句話:Lady l1 = new Lady(“l(fā)1”,c);

image.png

程序執(zhí)行到這里,首先在棧內存里面多了一個引用變量l1,l1里面裝著一個值尿赚,通過這個值可以找到在堆內存里面new出來的Lady對象散庶。l1就是這個Lady對象的引用蕉堰,l1指向Lady對象。在創(chuàng)建Lady對象時悲龟,調用Lady類的構造方法:Lady(String name,Animal pet)屋讶,其定義如下:

Lady(String name,Animal pet){

  this.name=name;

  this.pet=pet;

}

這個構造方法有兩個參數(shù),分別是String類型的name和Animal類型的pet须教,pet參數(shù)是一個父類對象的引用類型皿渗,這里把l1和c作為實參傳遞給了構造方法,接著在構造方法里面執(zhí)行this.name=name轻腺,把傳遞過來的l1由傳給Lady對象的name屬性乐疆,因此Lady對象的name屬性值為l1,這里也把前面new出來的那只Cat的引用c傳遞給了構造方法里面的參數(shù)pet贬养,接著在構造方法里面執(zhí)行this.pet=pet挤土,pet參數(shù)又把c傳過來的內容傳遞給Lady對象的pet屬性,因此pet屬性的屬性值就是可以找到Cat對象的地址误算,因此Lady對象的pet屬性也成為了Cat對象的引用對象了耕挨,通過pet里面裝著的值是可以找到Cat對象的,因此pet也指向了Cat尉桩,但并不是全部指向Cat,pet指向的只是位于Cat對象內部的Animal對象贪庙,這是因為在調用構造方法時蜘犁,是把c當成一個Animal對象的引用傳過來的,把c作為一個Animal對象傳遞給了pet止邮,所以得到的pet也是一個Animal對象的引用这橙,因此這個pet引用指向的只能是位于Cat對象里面的Animal對象。在我pet引用對象眼里导披,你Cat對象就是一只普通的Animal屈扎,訪問你的時候只能訪問得到你里面的name屬性,而你的eyesColor屬性我是訪問不到的撩匕,我能訪問到你的name屬性鹰晨,訪問的是位于你內部里面的父對象的name屬性,因為我pet引用本身就是一個父類對象的引用止毕,因此我可以訪問父類對象的全部屬性模蜡,而你子類對象Cat自己新增加的成員我pet引用是訪問不了的。不過現(xiàn)在我pet引用不去訪問你父類對象的成員變量name了扁凛,而是去訪問你的成員方法enjoy了忍疾。首先是使用Lady對象的引用l1去調用Lady對象的myPetEnjoy()方法,myPetEnjoy()方法定義如下:

public void myPetEnjoy(){

  pet.enjoy();

}

然后在myPetEnjoy()方法體里面又使用pet引用對象去調用父類對象里面的enjoy方法谨朝。

方法是放在代碼區(qū)(code seg)里面的卤妒,里面的方法就是一句句代碼甥绿。因此當使用pet****引用去訪問父類對象的方法時,首先是找到這個父類對象则披,然后看看它里面的方法到底在哪里存著共缕,找到那個方法再去執(zhí)行。這里頭就比較有意思了收叶,code seg里面有很多個enjoy方法骄呼,有父類的enjoy()方法,也有子類重寫了從父類繼續(xù)下來的enjoy()方法判没,那么調用的時候到底調用的是哪一個呢蜓萄?是根據(jù)誰來確定呢?注意:這是根據(jù)你實際當中的對象來確定的澄峰,你實際當中new出來的是誰嫉沽,就調用誰的enjoy方法,當你找這個方法的時候俏竞,通過pet引用能找得到這個方法绸硕,但調用代碼區(qū)里面的哪一個enjoy方法不是通過引用類型來確定的,如果是通過引用類型pet來確定魂毁,那么調用的肯定是Animal的enjoy()方法玻佩,可是現(xiàn)在是根據(jù)實際的類型來確定,我們的程序運行以后才在堆內存里面創(chuàng)建出一只Cat席楚,然后根據(jù)你實際當中new出來的類型來判斷我到底應該調用哪一個enjoy()方法咬崔。如果是根據(jù)實際類型,那么調用的就應該是Cat的enjoy()方法烦秩。如果是根據(jù)引用類型垮斯,那么調用的就應該是Animal的enjoy()方法。現(xiàn)在動態(tài)綁定這種機制指的是實際當中new的是什么類型只祠,就調用誰的enjoy方法兜蠕。所以說雖然你是根據(jù)我父類里面的enjoy方法來調用,可是實際當中卻是你new的是誰調用的就是誰的enjoy()方法抛寝。即實際當中調用的卻是子類里面重寫后的那個enjoy方法熊杨。當然,講一點更深的機制盗舰,你實際當中找這個enjoy方法的時候猴凹,在父類對象的內部有一個enjoy方法的指針,指針指向代碼區(qū)里面父類的Animal的enjoy方法岭皂,只不過當你new這個對象的時候郊霎,這個指針隨之改變,你new的是什么對象爷绘,這個指針就指向這個對象重寫后的那個enjoy方法书劝,所以這就叫做動態(tài)綁定进倍。只有在動起來的時候,也就是在程序運行期間购对,new出了這個對象了以后你才能確定到底要調用哪一個方法猾昆。我實際當中的地址才會綁定到相應的方法的地址上面,所以叫動態(tài)綁定骡苞。調這個方法的時候垂蜗,只要你這個方法重寫了,實際當中調哪一個解幽,要看你實際當中new的是哪個對象贴见,這就叫多態(tài),也叫動態(tài)綁定躲株。動態(tài)綁定帶來莫大的好處是使程序的可擴展性達到了最好片部,我們原來做這個可擴展性的時候,首先都是要在方法里面判斷一下這只動物是哪一類里面的動物霜定,通過if (object instanceof class)這樣的條件來判斷這個new出來的對象到底是屬于哪一個類里面的档悠,如果是一只貓,就調用貓的enjoy方法望浩,如果是一條狗辖所,就調用狗的enjoy方法。如果我現(xiàn)在增加了一個Bird類磨德,那么擴展的時候缘回,你又得在方法里面寫判斷這只鳥屬于哪一個類然后才能調用這只鳥的enjoy方法。每增加一個對象剖张,你都要在方法里面增加一段判斷這個對象到底屬于哪個類里面的代碼然后才能執(zhí)行這個對象相應的方法。即每增加一個新的對象揩环,都要改變方法里面的處理代碼搔弄,而現(xiàn)在,你不需要再改變方法里面的處理代碼了丰滑,因為有了動態(tài)綁定顾犹。你要增加哪一個對象,你實際當中把這個對象new出來就完了褒墨,不再用去修改對象的處理方法里面的代碼了炫刷。也就是當你實際當中要增加別的東西的時候,很簡單郁妈,你直接加上去就成了浑玛,不用去改原來的結構,你要在你們家大樓的旁邊蓋一個廚房噩咪,很簡單顾彰,直接在旁邊一蓋就行了极阅,大樓的主要支柱什么的你都不用動,這就可以讓可擴展性達到了極致涨享,這就為將來的可擴展打下了基礎筋搏,也只有動態(tài)綁定(多態(tài))這種機制能幫助我們做到這一點——讓程序的可擴展性達到極致。因此動態(tài)綁定是面向對象的核心厕隧,如果沒有動態(tài)綁定奔脐,那么面向對象絕對不可能發(fā)展得像現(xiàn)在這么流行,所以動態(tài)綁定是面向對象核心中的核心吁讨。

總結動態(tài)綁定(多態(tài)):動態(tài)綁定是指在“執(zhí)行期間”(而非編譯期間)判斷所引用的實際對象類型髓迎,根據(jù)其實際的類型調用其相應的方法。所以實際當中找要調用的方法時是動態(tài)的去找的挡爵,new的是誰就找誰的方法竖般,這就叫動態(tài)綁定。動態(tài)綁定幫助我們的程序的可擴展性達到了極致茶鹃。

多態(tài)的存在有三個必要的條件:

  1. 要有繼承(兩個類之間存在繼承關系涣雕,子類繼承父類)
  2. 要有重寫(在子類里面重寫從父類繼承下來的方法)
  3. 父類引用指向子類對象

這三個條件一旦滿足,當你調用父類里面被重寫的方法的時候闭翩,實際當中new的是哪個子類對象挣郭,就調用子類對象的方法(這個方法是從父類繼承下來后重寫后的方法)。

面向對象比較強調類和類之間疗韵,對象和對象之間的一種組織關系兑障,如果能把這種組織關系組織得比較好的話,你的程序想擴展性比較好蕉汪,比較健壯流译,維護性比較好這些都可以達到,關鍵看你的設計到底好還是不好者疤。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末福澡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驹马,更是在濱河造成了極大的恐慌革砸,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糯累,死亡現(xiàn)場離奇詭異算利,居然都是意外死亡,警方通過查閱死者的電腦和手機泳姐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門效拭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事允耿〗梵希” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵较锡,是天一觀的道長业稼。 經(jīng)常有香客問我,道長蚂蕴,這世上最難降的妖魔是什么低散? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮骡楼,結果婚禮上熔号,老公的妹妹穿的比我還像新娘。我一直安慰自己鸟整,他們只是感情好引镊,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著篮条,像睡著了一般弟头。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涉茧,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天赴恨,我揣著相機與錄音,去河邊找鬼伴栓。 笑死伦连,一個胖子當著我的面吹牛,可吹牛的內容都是我干的钳垮。 我是一名探鬼主播惑淳,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饺窿!你這毒婦竟也來了歧焦?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤短荐,失蹤者是張志新(化名)和其女友劉穎倚舀,沒想到半個月后叹哭,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忍宋,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年风罩,在試婚紗的時候發(fā)現(xiàn)自己被綠了糠排。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡超升,死狀恐怖入宦,靈堂內的尸體忽然破棺而出哺徊,到底是詐尸還是另有隱情,我是刑警寧澤乾闰,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布落追,位于F島的核電站,受9級特大地震影響涯肩,放射性物質發(fā)生泄漏轿钠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一病苗、第九天 我趴在偏房一處隱蔽的房頂上張望疗垛。 院中可真熱鬧,春花似錦硫朦、人聲如沸贷腕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泽裳。三九已至,卻和暖如春挚赊,著一層夾襖步出監(jiān)牢的瞬間诡壁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工荠割, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妹卿,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓蔑鹦,卻偏偏與公主長得像夺克,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嚎朽,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內容

  • 一:java概述:1铺纽,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境哟忍,java的開發(fā)工...
    ZaneInTheSun閱讀 2,662評論 0 11
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔狡门,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 2,771評論 2 9
  • 一:java概述: 1锅很,JDK:Java Development Kit其馏,java的開發(fā)和運行環(huán)境,java的開發(fā)...
    慕容小偉閱讀 1,796評論 0 10
  • 整理來自互聯(lián)網(wǎng) 1爆安,JDK:Java Development Kit叛复,java的開發(fā)和運行環(huán)境,java的開發(fā)工具...
    Ncompass閱讀 1,540評論 0 6
  • 剛剛過完六一,又迎來了一周的小假期褐奥,這可樂壞了孩子們咖耘。 早上孩子吃完飯,讀了半小時的書撬码,便去做作業(yè)...
    陳瑞慈媽媽閱讀 178評論 0 0