国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

java三大特性之多態

2019-11-06 06:51:25
字體:
來源:轉載
供稿:網友

多態的定義多態的三個必要條件多態的表現形式多態的種類多態的實現方式基于繼承實現的多態基于接口實現的多態經典案例答案分析多層父子調用的優先級

多態的定義

多態程序中定義的引用變量和通過該引用變量調用的方法所指向的具體類型和具體類型的方法在編程時并不確定,而只有在程序運行期間某一刻才能具體確定的情況稱之為多態。

寫的有點饒,但是可以看到幾個重點是引用的變量和該變量的方法在沒運行時我們是不確定它的具體類型的。

那么為什么會有這種情況呢,根據在繼承中的提現我們發現會發生這種情況的就是向下轉型的問題。 即;我們可以確定貓是動物,但是反過來如果別人給你是一只被袋子裝起來的動物(向上轉型)你是無法判斷它到底是貓還是小老虎(向下轉型)不是么。

多態的三個必要條件

因此多態出現的情況就很明顯了,它必須有一個前提場景才能發生;

實現多態有三個必要條件:繼承(extent)、重寫(overriding)、向上轉型

通過實例說明

public class Animal { public void fun1(){ System.out.Output

Animal 的Fun.....Cat 的Fun2...

從程序的運行結果中我們發現, a.fun1()首先是運行父類Animal中的fun1().然后再運行子類Cat中的fun2()。

所以對于多態我們可以總結如下:

指向子類的父類引用由于向上轉型了,它只能訪問父類中擁有的方法和屬性,而對于子類中存在而父類中不存在的方法,該引用是不能使用的,盡管是重載該方法。若子類重寫了父類中的某些方法,在調用這些方法的時候,必定是使用子類中定義的這些方法(動態連接、動態調用)。

多態的表現形式

java中的多態的表現形式一般分為兩種:overriding(重寫)和overloading(重載)

重寫overriding是父類和子類之間多態性的一種表現重載overloading是一個類中多態性的表現。

如果在子類中定義某方法與其父類有相同的名稱和參數,我們就可以這樣說此方法被子類重寫overriding,子類中的對象使用這個方法的時候,將調用子類中中的定義,此時對子類來說,父類中的方法定義如同被”屏蔽”了一樣(a不能調用fun1(String str)方法)。如果在一個類中定義了多個同名的方法,它們或有不同的參數或有不同的參數類型,則稱為方法的重載overloading。并且overloading的方式是可以改變返回值類型的,但是父類中并沒有這些重載的方法。

多態的種類

分為編譯時多態和運行時多態

多態的實現方式

兩種實現方式: - 基于繼承 - 基于接口

基于繼承實現的多態

上面的例子都是基于繼承實現的,當然下面這個也是基于繼承:

public class Wine { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public Wine(){ } public String drink(){ return "喝的是 " + getName(); } /** * 重寫toString() */ public String toString(){ return null; }}public class JNC extends Wine{ public JNC(){ setName("JNC"); } /** * 重寫父類方法,實現多態 */ public String drink(){ return "喝的是 " + getName(); } /** * 重寫toString() */ public String toString(){ return "Wine : " + getName(); }}public class JGJ extends Wine{ public JGJ(){ setName("JGJ"); } /** * 重寫父類方法,實現多態 */ public String drink(){ return "喝的是 " + getName(); } /** * 重寫toString() */ public String toString(){ return "Wine : " + getName(); }}public class Test { public static void main(String[] args) { //定義父類數組 Wine[] wines = new Wine[2]; //定義兩個子類 JNC jnc = new JNC(); JGJ jgj = new JGJ(); //父類引用子類對象 wines[0] = jnc; wines[1] = jgj; for(int i = 0 ; i < 2 ; i++){ System.out.println(wines[i].toString() + "--" + wines[i].drink()); } System.out.println("-------------------------------"); }}

OUTPUT:

Wine : JNC--喝的是 JNCWine : JGJ--喝的是 JGJ-------------------------------

在上面的代碼中JNC、JGJ繼承Wine,并且重寫了drink()、toString()方法,程序運行結果是調用子類中方法,輸出JNC、JGJ的名稱,這就是多態的表現。不同的對象可以執行相同的行為,但是他們都需要通過自己的實現方式來執行,這就要得益于向上轉型了。

我們都知道所有的類都繼承自超類Object,toString()方法也是Object中方法,當我們這樣寫時:Object o = new JGJ(); System.out.println(o.toString());

所以基于繼承實現的多態可以總結如下:對于引用子類的父類類型,在處理該引用時,它適用于繼承該父類的所有子類,子類對象的不同,對方法的實現也就不同,執行相同動作產生的行為也就不同。

基于接口實現的多態

繼承是通過重寫父類的同一方法的幾個不同子類來體現的,那么就可就是通過實現接口并覆蓋接口中同一方法的幾不同的類體現的。 在接口的多態中,指向接口的引用必須是指定這實現了該接口的一個類的實例程序,在運行時,根據對象引用的實際類型來執行對應的方法。 繼承都是單繼承,只能為一組相關的類提供一致的服務接口。但是接口可以是多繼承多實現,它能夠利用一組相關或者不相關的接口進行組合與擴充,能夠對外提供一致的服務接口。所以它相對于繼承來說有更好的靈活性。

這里就不寫代碼了,接口繼承,執行的方法根據具體的子類型來確定,借口本身是不能直接調用的,所以執行的具體方法根據傳遞的子類型來執行它的實現方法。

經典案例

這是一個非常變態的多態案例,作者寫得非常詳細:

http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx

public class A { public String show(D obj) { return ("A and D"); } public String show(A obj) { return ("A and A"); } }public class B extends A{ public String show(B obj){ return ("B and B"); } public String show(A obj){ return ("B and A"); } }public class C extends B{}public class D extends B{}public class Test { public static void main(String[] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println("1--" + a1.show(b)); System.out.println("2--" + a1.show(c)); System.out.println("3--" + a1.show(d)); System.out.println("4--" + a2.show(b)); System.out.println("5--" + a2.show(c)); System.out.println("6--" + a2.show(d)); System.out.println("7--" + b.show(b)); System.out.println("8--" + b.show(c)); System.out.println("9--" + b.show(d)); }}

答案

① A and A ② A and A ③ A and D ④ B and A ⑤ B and A ⑥ A and D ⑦ B and B ⑧ B and B ⑨ A and D

分析

①②③比較好理解,一般不會出錯。④⑤就有點糊涂了,為什么輸出的不是"B and B”呢?!!先來回顧一下多態性。 運行時多態性是面向對象程序設計代碼重用的一個最強大機制,動態性的概念也可以被說成“一個接口,多個方法”。Java實現運行時多態性的基礎是動態方法調度,它是一種在運行時而不是在編譯期調用重載方法的機制。 方法的重寫Overriding和重載Overloading是Java多態性的不同表現。重寫Overriding是父類與子類之間多態性的一種表現,重載Overloading是一個類中多態性的一種表現。如果在子類中定義某方法與其父類有相同的名稱和參數,我們說該方法被重寫(Overriding)。子類的對象使用這個方法時,將調用子類中的定義,對它而言,父類中的定義如同被“屏蔽”了。如果在一個類中定義了多個同名的方法,它們或有不同的參數個數或有不同的參數類型,則稱為方法的重載(Overloading)。Overloaded的方法是可以改變返回值的類型。

當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調用誰的成員方法,但是這個被調用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。 (但是如果強制把超類轉換成子類的話,就可以調用子類中新添加而超類沒有的方法了。)

好了,先溫習到這里,言歸正傳!

多層父子調用的優先級

上面的案例實際上涉及方法調用的優先問題

優先級由高到低依次為:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。讓我們來看看它是怎么工作的。

比如④,a2.show(b),a2是一個引用變量,類型為A,則this為a2,b是B的一個實例,于是它到類A里面找show(B obj)方法,沒有找到,于是到A的super(超類)找,而A沒有超類,因此轉到第三優先級this.show((super)O),this仍然是a2,這里O為B,(super)O即(super)B即A,因此它到類A里面找show(A obj)的方法,類A有這個方法,但是由于a2引用的是類B的一個對象,B覆蓋了A的show(A obj)方法,因此最終鎖定到類B的show(A obj),輸出為"B and A”。
上一篇:java運行機制

下一篇:java中循環遍歷

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鄄城县| 印江| 皮山县| 阿坝县| 永川市| 萝北县| 河间市| 静海县| 龙胜| 云梦县| 南充市| 丰原市| 赫章县| 义乌市| 九龙城区| 罗城| 农安县| 德江县| 雷山县| 乐亭县| 南丰县| 嘉鱼县| 垦利县| 民和| 罗定市| 宝兴县| 凌云县| 辉县市| 敖汉旗| 肃南| 伊川县| 桐庐县| 互助| 新昌县| 德格县| 永年县| 娄烦县| 调兵山市| 房山区| 南部县| 泗洪县|