日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

c java多态_浅谈Java多态

發(fā)布時間:2024/1/8 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c java多态_浅谈Java多态 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

什么是Java中的多態(tài)?又是一個紙老虎的概念,老套路,把它具體化,細(xì)分化,先想三個問題(注意,這里不是簡單的化整為零,而是要建立在學(xué)習(xí)一個新概念時的思考框架):

1.這個東西有什么用?用來干什么的?它的意義在哪里?(顯然,如果是沒用的東西,就沒必要浪費時間了;其實,弄懂了這個問題,就掌握了50%)

2.這個概念或者技能點怎么用?也就是它的表現(xiàn)形式,如關(guān)鍵字、修飾詞、語法什么的。。。(這個占25%)

3.這個東西在用的過程中,有哪些關(guān)鍵點和細(xì)節(jié)點?(是的,也占25%)

上面三個問題搞清楚了,剩下的就是去用了。。。“無他,但手熟爾。”

一、第一個問題:多態(tài)有什么用?它存在的意義是什么?

多態(tài)的作用:使代碼具有松耦合性,滿足開閉原則。(多態(tài),意味著一個對象有著多重特征,可以在特定的情況下,表現(xiàn)不同的狀態(tài),從而對應(yīng)著不同的屬性和方法。)WTF?又裝x!松耦合是什么鬼?還開閉原則?能不能直給?好吧,所謂的“耦合”就是,當(dāng)你擴展功能的時候,其他與之相應(yīng)的源代碼也要修改,有點像麻花一樣糾纏不清;“松耦合”是指你雖然擴展了,但不需要修改其他的代碼。這樣就達到了對擴展開放,對修改關(guān)閉的效果。

具體怎樣,看個例子就懂了:小強,一個農(nóng)村熱血青年,來到大城市打工,每天披星戴月,辛勤工作,終于存了些錢。于是小強帶著錢回到老家,請村東頭的媒婆王大娘給自己介紹對象。小強在焦急等待幾天之后,看到王大娘笑瞇瞇走過來,“強啊,大娘給你找到姑娘了”。。。

故事先講到這兒,我們用代碼來把這件事實現(xiàn)一下:

1 public class Girl{ //父類--姑娘

2 public int faceScore=60; //顏值

3 public int love=0;4 public void say(){ //自我介紹

5 System.out.println("hello world!");6 }7 public void addLove(){ //被求愛后,增加愛心值

8 }9 }10 public class HubeiGirl extends Girl{ //子類--湖北姑娘

11 public int faceScore=70;12 public voidsay(){13 System.out.println("我叫小紅,我很聰明,也很會做飯。我的愛心值:"+love);14 }15 public void addLove() { //重寫增加愛心值方法

16 love+=20;17 System.out.println("我的愛心值是:"+love);18 }19 public void cook(){ //特有方法--做飯

20 System.out.println("紅丸子,炸丸子,四喜丸子。。。");21 }22 }23 public class HunanGirl extends Girl{ //子類--湖南姑娘

24 public int faceScore=85;25 public voidsay(){26 System.out.println("我叫小倩,我很可愛,也很會唱歌。我的愛心值:"+love);27 }28 public void addLove() { //重寫增加愛心值方法

29 love+=10;30 System.out.println("我的愛心值是:"+love);31 }32 public void sing(){ //特有方法--唱歌

33 System.out.println("辣妹子辣~辣妹子辣~~");34 }35 }

代碼很簡單,一個姑娘父類,兩個子類分別是湖北姑娘和湖南姑娘,好,現(xiàn)在小強見了兩個姑娘想向她們分別表達愛意(被求愛后,愛心值會增加),該怎么實現(xiàn)?代碼如下:

1 public class XiaoQiang{ //小強類

2 public void courting(HubeiGirl b){ //向湖北姑娘表達愛意

3 b.addLove();4 }5 public void courting(HunanGirl n){ //向湖南姑娘表達愛意

6 n.addLove();7 }8 }9 public classTest{10 public static voidmain(String[] argrs){11 HubeiGirl xiaohong = newHubeiGirl();12 xiaohong.say();13 HunanGirl xiaoqian = newHunanGirl();14 xiaoqian.say();15 XiaoQiang qiang = newXiaoQiang();16 qiang.courting(xiaohong); //小強向湖北姑娘小紅表達愛意

17 qiang.courting(xiaoqian); //小強向湖南姑娘小倩表達愛意

18 }19 }

這里先定義了一個小強類,里面有兩個表達愛意的方法,參數(shù)是不同的對象類型,屬于重載。測試類中創(chuàng)建小紅、小倩和小強對象,運行結(jié)果如下:

由結(jié)果可以看到,傳入不同的對象類型參數(shù),小強調(diào)用不同的表達愛意的方法courting(),要求滿足,bingo!故事繼續(xù),王大娘的婚介事業(yè)已經(jīng)走出中國,在向國際化發(fā)展,王大娘認(rèn)識一個非洲姑娘瑪麗卡(如上圖),要把瑪麗卡介紹給小強。。。這要怎么實現(xiàn)?如果照著上面來:

1 public class AfricaGirl extends Girl{ //子類--非洲姑娘

2 public int faceScore=80;3 public voidsay(){4 System.out.println("我叫瑪麗卡,我很熱情,也很會跳舞。我的愛心值:"+love);5 }6 public void addLove() { //重寫增加愛心值方法

7 love+=15;8 System.out.println("我的愛心值是:"+love);9 }10 public void dance(){ //特有方法--跳舞

11 System.out.println("動起來!gogogogo for it!動起來!");12 }13 }14 public class XiaoQiang{ //小強類

15 public void courting(HubeiGirl b){ //向湖北姑娘表達愛意

16 b.addLove();17 }18 public void courting(HunanGirl n){ //向湖南姑娘表達愛意

19 n.addLove();20 }21 public void courting(AfricaGirl a){ //向非洲姑娘表達愛意

22 a.addLove();23 }24 }

這種做法是先定義子類非洲姑娘,這是必須的,在小強類里加了一個courting(AfricaGirl a)方法,這樣也能實現(xiàn)要求,但是,這樣有兩個問題:1.增加非洲姑娘類的時候,改動了小強類,不是松耦合,不滿足開閉原則;2.假如王大娘的業(yè)務(wù)發(fā)展的很好,要給小強介紹100個姑娘,難道要改變100次小強類,往里面加100個方法嗎?

所以,問題來了:要怎樣定義小強類,使得即使不斷增加姑娘也不用改動小強類?這里就要用到多態(tài)了,也是開篇第二個問題的答案。

二、第二個問題:多態(tài)怎么用?

其實,就一句話:父類類型的引用指向子類的對象。用多態(tài)的思想來定義上面的小強類,如下:

1 public class XiaoQiang{ //小強類

2 public void courting(Girl g){ //參數(shù)為父類類型

3 g.addLove();4 }5 }

很神奇,可以看到用多態(tài)的思想來做,只需要一個參數(shù)為父類Girl類型的方法就夠了,先來測試一下:

1 public classTest {2 public static voidmain(String[] args) {3 HubeiGirl xiaohong = newHubeiGirl();4 xiaohong.say();5 HunanGirl xiaoqian = newHunanGirl();6 xiaoqian.say();7 AfricaGirl malika = newAfricaGirl();8 malika.say();9 XiaoQiang qiang = newXiaoQiang();10 qiang.courting(xiaohong); //小強向湖北姑娘小紅表達愛意

11 qiang.courting(xiaoqian); //小強向湖南姑娘小倩表達愛意

12 qiang.courting(malika); //小強向非洲姑娘瑪麗卡表達愛意

13

14 }15 }

功能實現(xiàn),而且現(xiàn)在無論王大娘給小強介紹多少姑娘都不用修改小強類了。那么,為什么把參數(shù)從子類類型變成父類類型就能達到如此效果,就是多態(tài)呢?

這里我們先來仔細(xì)看一下使用父類作為方法形參實現(xiàn)多態(tài)的過程,以“小強向非洲姑娘瑪麗卡表達愛意”為例,qiang.courting(malika)執(zhí)行的時候,由于對象作為參數(shù)時,傳入的只是對象的引用,因此參數(shù)部分發(fā)生的是:Girl g = malika,也就是將父類類型Girl的引用g指向了子類對象malika(有的說法是,將子類類型的指針賦值給父類類型的指針,一個意思,一般指針是C和C++里的概念),是的,這就是Java機制允許的父類類型的引用指向子類的對象,就是多態(tài)。調(diào)用過程是:當(dāng)我們用一個父類型引用指向子類對象時,會先訪問子類中重寫的父類方法(父類的方法不會再執(zhí)行),如果子類沒有重寫父類的方法,才會執(zhí)行父類中的方法。而這種調(diào)用方式,就是多態(tài)的一種狀態(tài),叫做向上轉(zhuǎn)型,也是最為容易理解的一種多態(tài)方式。具體到上面的例子是,先訪問子類AfricaGirl中的重寫的addLove()方法,有,就不會再去訪問父類Girl中的addLove()方法了。

好,故事繼續(xù),老人家講過:凡是不以結(jié)婚為目的的談戀愛都是耍流氓。小強是正經(jīng)人,于是他要選一個最中意的姑娘,并把這個姑娘的對象返回出來,好讓王大娘進行其它操作。。。這個需求怎么實現(xiàn)?

1 public class XiaoQiang{ //小強類

2 public void courting(Girl g){ //參數(shù)為父類類型

3 g.addLove();4 }5

6 public Girl chooseGirl(int num) { //選擇姑娘的方法,返回值為Girl類型

7 switch(num) {8 case 1:9 HubeiGirl b = new HubeiGirl(); //num為1時,返回湖北姑娘的對象b

10 returnb;11 case 2:12 HunanGirl n = newHunanGirl();13 returnn;14 case 3:15 AfricaGirl a = newAfricaGirl();16 returna;17 default:18 break;19 }20 return null;21 }22 }

可以看到,小強類中增加了一個選擇姑娘的方法,根據(jù)不同的數(shù)字返回不同的子類姑娘對象,重點是它的返回值是父類Girl類型,這就是使用父類作為返回值實現(xiàn)多態(tài)。與上面使用父類作為方法形參實現(xiàn)多態(tài)相對,這里是在返回值的時候?qū)⒏割愵愋偷囊弥赶蜃宇悓ο蟆T跍y試類Test中調(diào)用一下:

1 public classTest {2 public static voidmain(String[] args) {3 XiaoQiang qiang = newXiaoQiang();4 Girl g = qiang.chooseGirl(1); //返回值是Girl類型,將返回值賦給Girl類型的引用g

5 qiang.courting(g); //表達愛意,增加愛心值

6 g.say();7 }8 }

可以看到,傳入數(shù)字1,返回的是湖北姑娘小紅,既然小紅很會做飯,那我們就調(diào)用一下她做飯的方法cook(),如下:

看樣子不太妙,報錯說cook()方法沒有定義,有人可能會問子類HubeiGirl中不是有cook()方法嗎,問題是現(xiàn)在的g是父類Girl類型的引用,而父類Girl中是沒有cook()方法的。這就涉及到向上轉(zhuǎn)型的一個特點:向上轉(zhuǎn)型后,父類類型的引用只能調(diào)用子類中的重寫的父類方法和父類中的方法,而不能調(diào)用子類中特有的方法。這里cook()是子類HubeiGirl特有的方法,所以不能調(diào)用。

娶個老婆居然不會做飯,小強肯定不高興,那該怎么辦?這里就需要將返回的父類型返回值強轉(zhuǎn)為子類型,并將其賦值給相應(yīng)子類型的引用。如下:

可以看到,調(diào)用cook()成功!如圖所示,將父類Girl類型的返回值強轉(zhuǎn)成子類HubeiGirl類型,再將其賦給子類HubeiGirl類型的引用g,就可以調(diào)用子類HubeiGirl中特有的方法了。這種將子類型對象向上轉(zhuǎn)型成父類型后,再將其轉(zhuǎn)回子類型的過程就是所謂的向下轉(zhuǎn)型。(注:不能直接將父類型對象轉(zhuǎn)型成子類型,一定要之前有向上轉(zhuǎn)型這個過程才行。)

好,故事講完,小強和小紅從此過上了幸福的生活。

三、第三個問題:使用多態(tài)的關(guān)鍵點和細(xì)節(jié)?

這個問題在二中已經(jīng)回答得差不多了,總結(jié)一下:

1.繼承:多態(tài)是發(fā)生在有繼承關(guān)系的子類和父類中的。

2.重寫:多態(tài)就是多種形態(tài)。也就是說,當(dāng)我們需要實現(xiàn)多態(tài)的時候,就需要有父類的方法被子類重寫。否則,如果沒有重寫的方法,就看不出多態(tài)的特性,一切按照父類的方法來,還不如不要繼承,直接在父類中添加相應(yīng)的方法,然后在實例化好了。

3.向上轉(zhuǎn)型:父類類型的引用指向子類的對象。

4.向下轉(zhuǎn)型:將子類型對象向上轉(zhuǎn)型成父類型后,再將其轉(zhuǎn)回子類型的過程。

5.在Java中有兩種形式可以實現(xiàn)多態(tài),繼承和接口。原理相同,本文只講了繼承情況。

四、經(jīng)典例題

既然學(xué)了東西就得用,不然那學(xué)東西有什么用。下面是一道關(guān)于多態(tài)的經(jīng)典例題,可以試一下不看答案能不能做出來:

1 public classA {2 publicString show(D obj) {3 return ("A and D");4 }5 publicString show(A obj) {6 return ("A and A");7 }8 }9

10 public classB extends A{11 publicString show(B obj){12 return ("B and B");13 }14 publicString show(A obj){15 return ("B and A");16 }17 }18

19 public classC extends B{20

21 }22 public classD extends B{23

24 }25

26 public classTest {27 public static voidmain(String[] args) {28 A a1 = newA();29 A a2 = newB();30 B b = newB();31 C c = newC();32 D d = newD();33

34 System.out.println("1--" +a1.show(b));35 System.out.println("2--" +a1.show(c));36 System.out.println("3--" +a1.show(d));37 System.out.println("4--" +a2.show(b));38 System.out.println("5--" +a2.show(c));39 System.out.println("6--" +a2.show(d));40 System.out.println("7--" +b.show(b));41 System.out.println("8--" +b.show(c));42 System.out.println("9--" +b.show(d));43 }44 }

運行結(jié)果如下:

1--A and A2--A and A3--A and D4--B and A5--B and A6--A and D7--B and B8--B and B9--A and D

不知道大家做對了幾個,有沒有像福爾摩斯推理探案一樣的感覺,現(xiàn)在就讓我們戴上獵鹿帽,叼上煙斗,拿著放大鏡開始吧,首先看看下面這張表示ABCD四個類關(guān)系的圖片:

由上圖可以看到:

1.B類中的show(A obj)是繼承并重寫了A類中的show(A obj)方法;

2.B類中的show(B obj)是重載,B相對A特有的方法;

3.B繼承了A的方法,C和D繼承了B的方法(包含了A的方法)。

現(xiàn)在來一個一個看:

1---- a1.show(b)

子類對象b作為參數(shù),而a1只能調(diào)用show(D obj)和show(A obj)兩個方法,顯然調(diào)用show(A obj),典型的多態(tài)應(yīng)用。

2----a1.show(c)

子類的子類對象c作為參數(shù),同樣的,a1只能show(D obj)和show(A obj)兩個方法,顯然調(diào)用show(A obj),這里表現(xiàn)的是多態(tài)中,子類對象不光可以賦給父類的引用,父類以上的引用都可以。而Java里最終極的父類是Object,所以,Object的引用可以指向任何對象。

3----a1.show(d)

子類的子類對象d作為參數(shù),同樣的,a1只能show(D obj)和show(A obj)兩個方法,顯然。。。額,里面有D類型作為參數(shù)的方法,所以顯然調(diào)用show(D?obj)。

4----a2.show(b)

A a2 = new B(); 其中,a2是父類型的引用指向了子類B類型的對象,多態(tài)的應(yīng)用,所以a2能調(diào)用的方法有:A類中的show(D obj)、B類中的show(A obj)兩個方法。為什么不能調(diào)用A類中的show(A?obj)方法?因為子類B已經(jīng)繼承并重寫了父類A類中的show(A?obj), 所以只會訪問子類B中的show(A?obj),不會再去訪問父類A中的show(A?obj)。為什么不能調(diào)用B類中的show(B obj)方法?因為此方法是子類B特有的方法,多態(tài)中父類A類型的引用a2不能訪問。現(xiàn)在是a2.show(b),參數(shù)是子類對象b,顯然調(diào)用B類中的show(A obj)方法。

5----a2.show(c)

同上,a2能調(diào)用的方法有:A類中的show(D obj)、B類中的show(A obj)兩個方法。B的子類對象c作為實參,顯然調(diào)用B類中的show(A obj)方法,類C的父類的父類型作為形參實現(xiàn)多態(tài)。

6---a2.show(d)

同上,a2能調(diào)用的方法有:A類中的show(D obj)、B類中的show(A obj)兩個方法。B的子類對象d作為實參,里面有D類型作為形參的方法,所以顯然調(diào)用A類中的show(D obj)方法。

7----b.show(b)

B b = new B();這個就是調(diào)用B類中的show(B obj)。

8----b.show(c)-------------------它仍然要按照繼承鏈中調(diào)用方法的優(yōu)先級來確認(rèn)。

B b = new B();其中,B類繼承了A類的方法,b可以調(diào)用的方法有:A類中的show(D obj)、B類中的show(A obj)、B類中的show(B obj)三個方法。B的子類對象c作為實參,調(diào)用父類B中的show(B obj),使用父類作為形參實現(xiàn)多態(tài)。為什么不能調(diào)用B類中的show(A obj)方法?類A是類C父類的父類,將A類型的引用指向類C的對象c不也是多態(tài)允許的?理論上是的,但實際情況是,現(xiàn)在有父類作為形參和父類的父類作為形參實現(xiàn)多態(tài)這兩種選擇。這時它就要按照按照繼承鏈中調(diào)用方法的優(yōu)先級來確認(rèn),父類B比父類的父類A優(yōu)先。其中優(yōu)先級為:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

9----b.show(d)

同上,b可以調(diào)用的方法有:A類中的show(D obj)、B類中的show(A obj)、B類中的show(B obj)三個方法。。。額,里面有D類型作為參數(shù)的方法,所以顯然調(diào)用A類中的show(D obj)。

總結(jié)

以上是生活随笔為你收集整理的c java多态_浅谈Java多态的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。