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并不存在于该对象继承链中
所以基于继承实现的多态可以总结如下:对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。
如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。
以上是java中多態的概念以及原理實現的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!