java中多態概念、實現原理詳解。本站提示廣大學習愛好者:(java中多態概念、實現原理詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是java中多態概念、實現原理詳解正文
一.什麼是多態?
1.多態的定義
指允許不同類的對象對同一消息做出響應。即同一消息可以根據發送對象的不同而采用多種不同的行為方式(發送消息就是函數調用)
2.多態的作用
消除類型之間的耦合關系
3.多態的說明
近代網絡小說泛濫,我們可以用它來舉一個例子
某日你看見你手機上有多部小說同時更新了,比如有大主宰,雪鷹領主,龍王傳說…在這裡我們可以描述成如下:
小說a=大主宰
小說b=雪鷹領主
小說c=龍王傳說
…
這裡所表現的就是多態,大主宰,雪鷹領主,龍王傳說都是小說的子類,我們僅僅可以通過小說這個父類就能夠引用不同的子類,這就是多態–我們只有在運行的時候才會知道引用變量所指向的具體實例對象
當然,這樣的理解是是遠遠不夠的,要對多態的理解入門就必須要明白是”向上轉型”
在上面的例子中,小說(XS)是父類,大主宰(DZZ),雪鷹領主(XYLZ),龍王傳說(LWCS)都是其子類 於是,我們定義如下代碼
DZZ a=new DZZ();
對於這段代碼應該都不會感覺到陌生,無非就是實例化了一個大主宰的對象 那麼對於如下的這段代碼呢?
XS a=new DZZ();
在這裡我們這樣理解,這裡定義了一個XS類型的a,讓它指向了DZZ對象實例。由於DZZ是繼承於XS,所以DZZ可以自動向上轉型為XS,所以a可以指向DZZ實例對象的。這樣做存在一個非常大的好處,在繼承中我們知道子類是父類的擴展,它可以提供比父類更加強大的功能,如果我們定義了一個指向子類的父類引用類型,那麼它除了能夠引用父類的共性外,還可以使用子類強大的功能
但是向上轉型也存在一些缺憾,那就是它必定會導致一些方法和屬性的丟失,而導致我們不能夠獲取它們。所以父類類型的運用可以調用父類中定義的所有屬性和方法,對於只存在與子類中的方法和屬性它就望塵莫及了
public class XS {
public void fun1() {
System.out.println("XS中的fun1");
fun2();
}
public void fun2() {
System.out.println("XS中的fun2");
}
}
public class DZZ extends XS{
/*
* 子類重載父類方法
* 父類中不存在該方法,向上轉型後,父類是不能引用該方法的
*/
public void fun1(String a) {
System.out.println("DZZ中的fun1");
fun2();
}
/*
* 子類重寫父類方法
* 調用必定使用這個方法
*/
public void fun2() {
System.out.println("DZZ中的fun2");
}
}
public class DuoTaiTest {
public static void main(String[] args) {
XS a=new DZZ();
a.fun1();
}
}
output:
XS中的fun1
DZZ中的fun2
所以對於多態我們可以總結如下:
指向子類的父類引用由於向上轉型了,它只能訪問父類中擁有的方法和屬性,而對於子類中存在而父類中不存在的方法,該引用是不能使用的,盡管是重載該方法。若子類重寫了父類中的某些方法,在調用該些方法的時候,必定是使用子類中定義的這些方法(動態連接,動態調用)
對於面向對象,多態分為編譯時多態和運行時多態,其中編輯時多態是靜態的,主要是指方法的重載,它是根據參數列表的不同來區分不同的函數,通過編輯之後會變成兩個不同的函數,在運行時談不上多態。而運行時多態是動態的,它是通過動態綁定來實現的,也就是我們所說的多態性。
二.多態的實現
1.實現條件
在剛剛開始就剃刀了繼承在為多態的實現做了准備。子類Child繼承父類Father,我們可以編寫一個指向子類的父類類型引用,該引用既可以處理父類Father對象,也可以處理子類Child對象,當相同的消息發送給子類或者父類對象時,該對象就會根據自己所屬的引用而執行不同的行為,這就是多態。即多態性就是相同的消息使得不同的類做出不同的響應
Java實現多態有三個必要條件:繼承,重寫,向上轉型
繼承:在多態中必須存在有繼承關系的子類和父類
重寫:子類對父類中某些方法進行重新定義,在調用這些方法時就會調用子類的方法
向上轉型:在多態中需要將子類的引用賦給父類對象,只有這樣該引用才能夠具備技能調用父類的方法和子類的方法
只有滿足了上述三個條件,我們才能夠在同一個繼承結構中使用同一的邏輯實現代碼處理不同的對象,從而達到執行不同的行為
對於Java而言,它多態的實現機制遵循一個原則:當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,但是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法
2.實現形式
繼承
public class XS {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public XS() {
}
public String drink() {
return "你看的小說名字:"+getName();
}
public String toString() {
return null;
}
}
public class DZZ extends XS{
public DZZ() {
setName("DZZ");
}
public String drink() {
return "你看的小說名字:"+getName();
}
public String toString() {
return "小說名:"+getName();
}
}
public class XYLZ extends XS{
/**
*
*/
public XYLZ() {
setName("XYLZ");
}
public String drink() {
return "你看的小說名字:"+getName();
}
public String toString() {
return "小說名:"+getName();
}
}
public class DuoTaiTest {
public static void main(String[] args) {
XS [] xs=new XS[2];
DZZ a=new DZZ();
XYLZ b=new XYLZ();
xs[0]=a;
xs[1]=b;
for(int i=0;i<2;i++) {
System.out.println(xs[i].toString()+"::::"+xs[i].drink());
}
System.out.println("-------------------");
}
}
ouput:
小說名:DZZ::::你看的小說名字:DZZ
小說名:XYLZ::::你看的小說名字:XYLZ
-------------------
在上面的代碼中DZZ,XYLZ繼承XS 並且重寫了drink(),toString()方法,程序運行結果是調用子類中方法,輸出DZZ,XYLZ的名稱,這就是多態的表現。不同的對象可以執行相同的行為,但是他們都需要通過自己的實現方式來執行,這就要得益於向上轉型了
我們都知道所有的類都繼承自超類Object,toString()方法也是Object中方法,當我們這樣寫時:
Object o = new DZZ(); System.out.println(o.toString()); output: 小說名:DZZ
Object,XS,DZZ三者繼承鏈關系是:DZZ—>XS—>Object。所以我們可以這樣說:當子類重寫父類的方法被調用時,只有對象繼承鏈中的最末端的方法才會被調用。但是注意如果這樣寫:
Object o = new xs(); System.out.println(o.toString()); output: null//因為DZZ並不存在於該對象繼承鏈中
所以基於繼承實現的多態可以總結如下:對於引用子類的父類類型,在處理該引用時,它適用於繼承該父類的所有子類,子類對象的不同,對方法的實現也就不同,執行相同動作產生的行為也就不同。
如果父類是抽象類,那麼子類必須要實現父類中所有的抽象方法,這樣該父類所有的子類一定存在統一的對外接口,但其內部的具體實現可以各異。這樣我們就可以使用頂層類提供的統一接口來處理該層次的方法。
本篇文章的內容希望能給需要的朋友一些幫助