多態(tài)相對于封裝和繼承這兩個名詞就不是那么生活化了。這個詞最早是一個生物的專業(yè)用詞,它的指的是同一個物種在不同的環(huán)境當(dāng)中可能出現(xiàn)的多樣化表現(xiàn)。那么衍生到了面向?qū)ο缶幊讨校暮x呢,我們用一句經(jīng)典來話來描述:相同的行為,不同的實現(xiàn)。
成都創(chuàng)新互聯(lián)公司是一家專注于網(wǎng)站設(shè)計制作、成都網(wǎng)站建設(shè)與策劃設(shè)計,藤縣網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)公司做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:藤縣等地區(qū)。藤縣做網(wǎng)站價格咨詢:189820811081、多態(tài)指的是行為的多樣性,沒有屬性多態(tài)這一說;
2、相同的行為指的是同名方法,也就是說方法名相同,我們就認(rèn)為這是相同的行為。 由此,我們前面學(xué)習(xí)的方法重載和方法重寫其實都是多態(tài)的表現(xiàn)。
最近面試看到的:屬性能不能重寫?1、首先這個說法不專業(yè),重寫特指的是方法,但是它要描述的意思其實我們懂,那就是父類中定義了一個屬性,子類能不能再定義一個同名屬性把它給覆蓋掉;
2、在語法上,這是可以的,不會報錯。但是子類定義的屬性是不會把父類定義的屬性給覆蓋掉;而是兩個屬性同時存在于對象身上,父類定義的存在于子類對象的父類對象部分(上半截),子類定義的存在于子類對象的子類特有部分(下半截)。那么,如何區(qū)分呢?用this.訪問子類定義的該屬性;用super.訪問父類定義的該屬性。
3、在實際場景中,這種設(shè)計是沒有意義的。因為父類定義了一個屬性,子類通過繼承自動擁有了這個屬性,那么子類再去定義一個一摸一樣的屬性是沒有任何意義的,屬于重復(fù)勞動。這是屬于子類的設(shè)計人員沒有理解父類設(shè)計的意圖。
多態(tài)的意義封裝是面向?qū)ο蟮幕A(chǔ); 繼承是在封裝的基礎(chǔ)上,實現(xiàn)代碼的復(fù)用性; 多態(tài)考量的是代碼的豐富度。
多態(tài)分為兩種: 1、靜態(tài)多態(tài);2、動態(tài)多態(tài)。
這里的靜態(tài)和我們前面學(xué)習(xí)的static關(guān)鍵字沒有關(guān)系,它描述的是:在編譯期既能確定某個多態(tài)方法的具體執(zhí)行效果; 這里的動態(tài)多態(tài)是指在運行期,根據(jù)綁定對象的不同,才能確定多態(tài)方法執(zhí)行的效果。
我們在前面學(xué)過的方法的重載和方法的重寫都是屬于靜態(tài)多態(tài)。靜態(tài)多態(tài)雖然有豐富度的體現(xiàn),但是是不夠的,因為它在編譯期就把執(zhí)行效果固定下來了。而我們以后用得更多的是動態(tài)多態(tài)。
動態(tài)多態(tài)是由兩個技術(shù)合并使用才有的效果:動態(tài)綁定技術(shù) + 方法的重寫。
動態(tài)綁定技術(shù)首先我們從現(xiàn)象上來看一個效果: 本類引用 指向 本類對象; 父類引用 指向 子類對象;
在Java當(dāng)中只有這兩種情況,也就是說賦值符號左右兩端如果類型不一致,那么只有后面這種情況。
從內(nèi)存上解釋為什么父類引用可以指向子類對象呢? 既然是父子關(guān)系,還是在做繼承,那么還是跟內(nèi)存疊加有關(guān)系。每一個子類對象的上半截都是一個完整的父類對象部分,當(dāng)父類引用指過去的時候,是能夠看到完整的父類對象信息的。
沒有繼承關(guān)系的類,不能保證A類引用指到B類對象,能看到B類對象中有A類定義的內(nèi)容,所以不允許!
子類引用指向父類對象的時候,父類對象里面沒有子類特有部分,所以缺失了內(nèi)容,也不允許!
從場景上解釋一個對象屬于子類,一定也屬于它的父類。子和父是is-a關(guān)系,這是說得通的。
但是一個對象屬于父類,你能保證它一定屬于子類嗎?
而沒有繼承關(guān)系的,那就更說不通的了,比如:指鹿為馬。 明明是一個鹿的對象,你偏要用馬的引用去指向它,肯定是不對的。你可以說它是動物、可以說它是寵物、因為鹿is-a動物;鹿 is-a 寵物;都是可行的,但鹿 is not a 馬。
動態(tài)體現(xiàn)在哪兒?如果我們手上現(xiàn)在擁有一個父類引用,那么我們就不能確定這個引用到底是指向哪一個具體的對象的了。
它既可能指向自己類型的對象,也可能指向自己的各種子類對象。而自己的某個方法,是可以被子類重寫成不同的實現(xiàn)效果的。那么用這個引用執(zhí)行重寫方法,也就不能確定到底重寫前還是重寫后,是A子類重寫后,還是其它子類重寫后的效果了。只有等程序運行起來以后,根據(jù)該引用具體綁定的對象到底是誰,才能夠運行出具體的效果。--- 這就是動態(tài)的體現(xiàn)。
語法細(xì)節(jié)轉(zhuǎn)型技術(shù)
賦值符號左右兩端數(shù)據(jù)類型不一致,就會發(fā)生數(shù)據(jù)類型轉(zhuǎn)換。 父類引用 = 子類對象 也是兩端數(shù)據(jù)類型不一致,所以也屬于轉(zhuǎn)型技術(shù)。
我們用我們前面學(xué)習(xí)的基本數(shù)據(jù)類型轉(zhuǎn)型技術(shù)去推衍現(xiàn)在的引用數(shù)據(jù)類型的轉(zhuǎn)型技術(shù)。
基本數(shù)據(jù)類型轉(zhuǎn)型技術(shù)
1、前提:不是所有基本數(shù)據(jù)類型之間都能夠進(jìn)行轉(zhuǎn)型,boolean不參與的;
2、自動類型轉(zhuǎn)換 小類型值 賦值給 大類型的變量強調(diào):這里的大小 是 數(shù)據(jù)類型能表示的范圍的大小,而不是空間的大小。
int num = 'A'; float f = num; double d = 100;
效果:不需要使用任何特殊語法,直接完成類型轉(zhuǎn)換并且賦值成功。
3、強制類型轉(zhuǎn)換 大類型的值 賦值給 小類型的變量
效果: 3-1、直接書寫后,編譯報錯; 3-2、使用(目標(biāo)類型)的強轉(zhuǎn)語法,編譯才能夠通過; 3-3、運行的效果是有風(fēng)險性的,精度有可能丟失。
引用數(shù)據(jù)類型轉(zhuǎn)型技術(shù)
1、前提:不是所有引用數(shù)據(jù)類型之間都能夠做轉(zhuǎn)型,只有有繼承關(guān)系的類型之間才可以;
2、自動類型轉(zhuǎn)換 子類對象 賦值給 父類引用 子類表示的范圍 是小于 父類表示的范圍,所以仍然是把小的數(shù)據(jù)值交給大的變量。與基本數(shù)據(jù)類型的自動轉(zhuǎn)換要求是一摸一樣的。
只是說它有另一個特殊的名字,又叫做“向上轉(zhuǎn)型”而已。因為在繼承樹上,父類在上,子類在下;
效果:不需要使用任何特殊語法,直接完成類型轉(zhuǎn)換并且賦值成功。
3、強制類型轉(zhuǎn)換 大類型的值 賦值給 小類型的引用
又被稱為"向下轉(zhuǎn)型".
效果: 1、直接書寫后,編譯報錯; 2、使用(目標(biāo)類型)的強轉(zhuǎn)語法,編譯才能夠通過; 3、運行的效果是有風(fēng)險性的,風(fēng)險性是運行時報錯(ClassCastException),中斷程序的執(zhí)行。
對風(fēng)險性探討:1、我們發(fā)現(xiàn)并不是每次強轉(zhuǎn)都一定成功,那么情況時如何的呢? 要想強轉(zhuǎn)以后,編譯通過且運行也通過,只有一種情況,那就是:最終的內(nèi)存結(jié)果只能是本類引用指向本類對象。
2、強轉(zhuǎn)語法只是在編譯期進(jìn)行一個強制性的語法說明,說明什么呢?告訴編譯器,我這個父類引用確實是指向的某種子類對象。
3、但是運行起來以后,如果滿足你的強制說明,那么沒有問題運行成功;如果不滿足你的強制說明,那么就會運行失敗,報出ClassCastException。
強調(diào):強轉(zhuǎn)語法不是把A類對象變成B對象,只是在編譯期達(dá)成的一個口頭約束而已。
父類引用指向子類對象,我們能訪問什么呢?
1、父類引用只能看到子類對象從父類繼承而來的屬性和行為,當(dāng)然要受訪問修飾符限制;注意:子類對象身上是有子類特有屬性和行為的,只是站在父類引用的角度上看不到而已。
2、要想看到,要把引用換成子類引用,這個時候要使用強轉(zhuǎn)語法,同時還必須保證運行起來以后真正給出的對象是符合強轉(zhuǎn)語法的。
3、特例是在父類中定義,被子類重寫的行為。由于這個行為是定義在父類中,所以父類引用能看到;而對象又是子類對象,所以執(zhí)行的效果是子類重寫后的效果。
練習(xí):書寫一個寵物類Pet,擁有一個叫的行為;書寫Pet的兩個子類Dog和Cat,分別實現(xiàn)叫的行為。再書寫一個主人類Master,擁有一個寵物對象,主人有一個行為是喂養(yǎng)feed,在該方法中調(diào)用自己寵物叫的行為。最后,在main方法中測試。
instanceof
在練習(xí)當(dāng)中,我們看到在有的場景里面,確實會存在需要強轉(zhuǎn)的情況。但是,強轉(zhuǎn)又有風(fēng)險度,所以,我們需要先判斷類型是否匹配,這就要用到instanceof了。
instanceof是一個關(guān)鍵字,也是一個運算符。它是專門用來判斷一個對象是否屬于某個類型的,運算后的結(jié)果是boolean型結(jié)果。
語法: 對象 instanceof 類型
instanceof是專門用來規(guī)避強轉(zhuǎn)帶來的ClassCastException風(fēng)險的,類似于非空判斷專門用來解決NullPointerException風(fēng)險的。
多態(tài)的應(yīng)用多態(tài)參數(shù)
當(dāng)我們在設(shè)計參數(shù)的時候,把參數(shù)的類型設(shè)計為父類類型,那么所有的子類對象都能夠通過這個參數(shù),傳遞到這個方法里面去。
? public void cure(角色 r){ ? ? ?if(r instanceof 士兵){ ? ? ? }else if(.....){ ? ? ? } ? } ?
這樣的多態(tài)應(yīng)用帶來了面向?qū)ο笤O(shè)計中非常重要的一個原則:開閉原則。
開閉原則:Software should be opened for extension, but closed for modification。
軟件對于擴展來說應(yīng)該是開放的,對于修改來說應(yīng)該是關(guān)閉。
也就是說好的軟件設(shè)計,應(yīng)該能夠可以隨著業(yè)務(wù)的擴展去增加新的功能,但是不應(yīng)該修改已有的功能。
多態(tài)集合
int[] array = new int[10];
Object[] arrayObj = new Object[10];
可以解決數(shù)組只能存放同一數(shù)據(jù)類型元素的問題。
補一下 switch的新語法 var關(guān)鍵字Java語言和JavaScript語言有一個很重要的區(qū)別: Java語言是強類型的編程語言;而JS是弱類型的。
int num = 10; String msg = "hello";
var num = 10; var name = "zhang3"; var pi = 3.14; ? num = "hello"; ?
在15年左右的時候,Java想去學(xué)習(xí)JS的這種聲明變量的簡便性,所以它也引入了var關(guān)鍵字來聲明變量。
但問題是,Java本身是強類型的,引入了以后又不能改變它的強類型本質(zhì),所以導(dǎo)致這個關(guān)鍵字不倫不類有很多限制。
1、必須要對var聲明的變量馬上賦值,因為編譯器是根據(jù)這個賦的值的類型才能判定這個變量是什么數(shù)據(jù)類型的;
2、一旦賦值成功后,這個變量的類型就被確定了,后面也不能更改,也不能存放其它類型的數(shù)據(jù)值;
3、var聲明的變量只能是局部變量,不能聲明為屬性的類型,也不能聲明為參數(shù)的類型。
4、所以在java中這個var變量的使用就沒有啥意義了。 唯一的意義可能僅僅在于如果一個局部變量的類型名很長的時候,可以幫助我們少寫點代碼。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
文章名稱:Java多態(tài)-創(chuàng)新互聯(lián)
文章出自:http://jinyejixie.com/article24/jgpje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、品牌網(wǎng)站建設(shè)、網(wǎng)站設(shè)計、網(wǎng)站改版、網(wǎng)頁設(shè)計公司、企業(yè)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容