用一句話概括就是:事物在運(yùn)行過程中存在不同的狀態(tài)。多態(tài)的存在有三個(gè)前提:
1.要有繼承關(guān)系
2.子類要重寫父類的方法
3.父類引用指向子類對(duì),
但是其中又有很多細(xì)節(jié)需要注意驼壶。首先我們定義兩個(gè)類收苏,一個(gè)父類Animal廉嚼,一個(gè)子類Cat。
以上的三段代碼充分體現(xiàn)了多態(tài)的三個(gè)前提倒戏,即:
1怠噪、存在繼承關(guān)系
Cat類繼承了Animal類
2、子類要重寫父類的方法
子類重寫(override)了父類的兩個(gè)成員方法eat()杜跷,sleep()傍念。其中eat()是非靜態(tài)的矫夷,sleep()是靜態(tài)的(static)。
3憋槐、父類數(shù)據(jù)類型的引用指向子類對(duì)象
測(cè)試類Demo_Test1中 Animal am = new Cat();語(yǔ)句在堆內(nèi)存中開辟了子類(Cat)的對(duì)象双藕,并把棧內(nèi)存中的父類(Animal)的引用指向了這個(gè)Cat對(duì)象。
到此阳仔,滿足了Java多態(tài)的的必要三個(gè)前提忧陪。
如果再深究一點(diǎn)呢,我們可以看看上面測(cè)試類的輸出結(jié)果近范,或許對(duì)多態(tài)會(huì)有更深層次的認(rèn)識(shí)嘶摊。猜一猜上面的結(jié)果是什么。
那么我們可以根據(jù)以上情況總結(jié)出多態(tài)成員訪問的特點(diǎn):
成員變量
編譯看左邊(父類),運(yùn)行看左邊(父類)
成員方法
編譯看左邊(父類)评矩,運(yùn)行看右邊(子類)叶堆。動(dòng)態(tài)綁定
靜態(tài)方法
編譯看左邊(父類),運(yùn)行看左邊(父類)斥杜。
(靜態(tài)和類相關(guān)虱颗,算不上重寫,所以蔗喂,訪問還是左邊的)
只有非靜態(tài)的成員方法,編譯看左邊,運(yùn)行看右邊
那么多態(tài)有什么弊端呢忘渔?有的,即多態(tài)后不能使用子類特有的屬性和方法缰儿。往上面的代碼看辨萍,子類Cat有一個(gè)特有的屬性String name = "tomCat"; 并且還有一個(gè)特有的抓老鼠的方法catchMouse()。但是在測(cè)試類(Demo_Test)中返弹,我們嘗試調(diào)用子類特有的方法catchMouse()和打印子類特有的成員屬性String name = "tomCat"; 就會(huì)報(bào)錯(cuò)锈玉。
am.catchMouse();
System.out.println(am.name);
原因就是多態(tài)的弊端,就是:不能使用子類特有的成員屬性和子類特有的成員方法义起。
如果在代碼執(zhí)行過程中還想使用Cat類中特有的屬性String name和它特有的成員方法catchMouse()了怎么辦呢拉背?那我們就可以把這個(gè)父類引用指向了子類對(duì)象的家伙am再?gòu)?qiáng)制變回Cat類型。這樣am就是Cat類型的引用了默终,指向的也是Cat對(duì)象了椅棺,自然也能使用Cat類的一切屬性和一切的成員方法。
很明顯齐蔽,執(zhí)行強(qiáng)轉(zhuǎn)語(yǔ)句Cat ct = (Cat)am;之后两疚,ct就指向最開始在堆內(nèi)存中創(chuàng)建的那個(gè)Cat類型的對(duì)象了。這就是多態(tài)的魅力吧含滴,雖然它有缺點(diǎn)诱渤,但是它確實(shí)十分靈活,減少多余對(duì)象的創(chuàng)建谈况,不用說為了使用子類的某個(gè)方法又去重新再堆內(nèi)存中開辟一個(gè)新的子類對(duì)象勺美。