




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、Java的多態(tài)性面向?qū)ο缶幊逃腥齻€特征,即封裝、繼承和多態(tài)。 封裝隱藏了類的內(nèi)部實現(xiàn)機制,從而可以在不影響使用者的前提下改變類的內(nèi)部結(jié)構(gòu),同時保護了數(shù)據(jù)。 繼承是為了重用父類代碼,同時為實現(xiàn)多態(tài)性作準備。那么什么是多態(tài)呢? 方法的重寫、重載與動態(tài)連接構(gòu)成多態(tài)性。Java之所以引入多態(tài)的概念,原因之一是它在類的繼承問題上和C+不同,后者允許多繼承,這確實給其帶來的非常強大的功能,但是復雜的繼承關(guān)系也給C+開發(fā)者帶來了更大的麻煩,為了規(guī)避風險,Java只允許單繼承,派生類與基類間有IS-A的關(guān)系(即“貓”is a “動物”)。這樣做雖然保證了繼承關(guān)系的簡單明了,但是勢必在功能上有很大的限制,所以,
2、Java引入了多態(tài)性的概念以彌補這點的不足,此外,抽象類和接口也是解決單繼承規(guī)定限制的重要手段。同時,多態(tài)也是面向?qū)ο缶幊痰木杷凇?要理解多態(tài)性,首先要知道什么是“向上轉(zhuǎn)型”。 我定義了一個子類Cat,它繼承了Animal類,那么后者就是前者是父類。我可以通過Cat c = new Cat();實例化一個Cat的對象,這個不難理解。但當我這樣定義時:Animal a = new Cat();這代表什么意思呢? 很簡單,它表示我定義了一個Animal類型的引用,指向新建的Cat類型的對象。由于Cat是繼承自它的父類Animal,所以Animal類型的引用是可以指向Cat類型的對象的。那么這樣
3、做有什么意義呢?因為子類是對父類的一個改進和擴充,所以一般子類在功能上較父類更強大,屬性較父類更獨特,定義一個父類類型的引用指向一個子類的對象既可以使用子類強大的功能,又可以抽取父類的共性。所以,父類類型的引用可以調(diào)用父類中定義的所有屬性和方法,而對于子類中定義而父類中沒有的方法,它是無可奈何的;同時,父類中的一個方法只有在在父類中定義而在子類中沒有重寫的情況下,才可以被父類類型的引用調(diào)用;對于父類中定義的方法,如果子類中重寫了該方法,那么父類類型的引用將會調(diào)用子類中的這個方法,這就是動態(tài)連接??聪旅孢@段程序:class Father public void func1() func2();
4、/這是父類中的func2()方法,因為下面的子類中重寫了該方法 /所以在父類類型的引用中調(diào)用時,這個方法將不再有效 /取而代之的是將調(diào)用子類中重寫的func2()方法 public void func2() System.out.println("AAA"); class Child extends Father /func1(int i)是對func1()方法的一個重載 /由于在父類中沒有定義這個方法,所以它不能被父類類型的引用調(diào)用 /所以在下面的main方法中child.func1(68)是不對的 public void func1(int i) System.out.
5、println("BBB"); /func2()重寫了父類Father中的func2()方法 /如果父類類型的引用中調(diào)用了func2()方法,那么必然是子類中重寫的這個方法 public void func2() System.out.println("CCC"); public class PolymorphismTest public static void main(String args) Father child = new Child(); child.func1();/打印結(jié)果將會是什么? 上面的程序是個很典型的多態(tài)的例子。子類Child繼
6、承了父類Father,并重載了父類的func1()方法,重寫了父類的func2()方法。重載后的func1(int i)和func1()不再是同一個方法,由于父類中沒有func1(int i),那么,父類類型的引用child就不能調(diào)用func1(int i)方法。而子類重寫了func2()方法,那么父類類型的引用child在調(diào)用該方法時將會調(diào)用子類中重寫的func2()。 那么該程序?qū)蛴〕鍪裁礃拥慕Y(jié)果呢?很顯然,應(yīng)該是“CCC”。 對于多態(tài),可以總結(jié)它為:一、使用父類類型的引用指向子類的對象; 二、該引用只能調(diào)用父類中定義的方法和變量; 三、如果子類中重寫了父類中的一個方法,那么在調(diào)用這個
7、方法的時候,將會調(diào)用子類中的這個方法;(動態(tài)連接、動態(tài)調(diào)用) 四、變量不能被重寫(覆蓋),”重寫“的概念只針對方法,如果在子類中”重寫“了父類中的變量,那么在編譯時會報錯。 *多態(tài)詳解(整理)2008-09-03 19:29多態(tài)是通過: 1 接口 和 實現(xiàn)接口并覆蓋接口中同一方法的幾不同的類體現(xiàn)的 2 父類 和 繼承父類并覆蓋父類中同一方法的幾個不同子類實現(xiàn)的.一、基本概念 多態(tài)性:發(fā)送消息給某個對象,讓該對象自行決定響應(yīng)何種行為。 通過將子類對象引用賦值給超類對象引用變量來實現(xiàn)動態(tài)方法調(diào)用。 java 的這種機制遵循一個原則:當超類對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的
8、類型決定了調(diào)用誰的成員方法,但是這個被調(diào)用的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法。 1. 如果a是類A的一個引用,那么,a可以指向類A的一個實例,或者說指向類A的一個子類。 2. 如果a是接口A的一個引用,那么,a必須指向?qū)崿F(xiàn)了接口A的一個類的實例。 二、Java多態(tài)性實現(xiàn)機制 SUN目前的JVM實現(xiàn)機制,類實例的引用就是指向一個句柄(handle)的指針,這個句柄是一對指針: 一個指針指向一張表格,實際上這個表格也有兩個指針(一個指針指向一個包含了對象的方法表,另外一個指向類對象,表明該對象所屬的類型); 另一個指針指向一塊從java堆中為分配出來內(nèi)存空間。 三、總結(jié) 1、通
9、過將子類對象引用賦值給超類對象引用變量來實現(xiàn)動態(tài)方法調(diào)用。 DerivedC c2=new DerivedC(); BaseClass a1= c2; /BaseClass 基類,DerivedC是繼承自BaseClass的子類 a1.play(); /play()在BaseClass,DerivedC中均有定義,即子類覆寫了該方法 分析: * 為什么子類的類型的對象實例可以覆給超類引用? 自動實現(xiàn)向上轉(zhuǎn)型。通過該語句,編譯器自動將子類實例向上移動,成為通用類型BaseClass; * a.play()將執(zhí)行子類還是父類定義的方法? 子類的。在運行時期,將根據(jù)a這個對象引用實際的類型來獲取對應(yīng)
10、的方法。所以才有多態(tài)性。一個基類的對象引用,被賦予不同的子類對象引用,執(zhí)行該方法時,將表現(xiàn)出不同的行為。 在a1=c2的時候,仍然是存在兩個句柄,a1和c2,但是a1和c2擁有同一塊數(shù)據(jù)內(nèi)存塊和不同的函數(shù)表。 2、不能把父類對象引用賦給子類對象引用變量 BaseClass a2=new BaseClass(); DerivedC c1=a2;/出錯 在java里面,向上轉(zhuǎn)型是自動進行的,但是向下轉(zhuǎn)型卻不是,需要我們自己定義強制進行。 c1=(DerivedC)a2; 進行強制轉(zhuǎn)化,也就是向下轉(zhuǎn)型. 3、記住一個很簡單又很復雜的規(guī)則,一個類型引用只能引用引用類型自身含有的方法和變量。 你可能說這
11、個規(guī)則不對的,因為父類引用指向子類對象的時候,最后執(zhí)行的是子類的方法的。 其實這并不矛盾,那是因為采用了后期綁定,動態(tài)運行的時候又根據(jù)型別去調(diào)用了子類的方法。而假若子類的這個方法在父類中并沒有定義,則會出錯。 例如,DerivedC類在繼承BaseClass中定義的函數(shù)外,還增加了幾個函數(shù)(例如 myFun()) 分析: 當你使用父類引用指向子類的時候,其實jvm已經(jīng)使用了編譯器產(chǎn)生的類型信息調(diào)整轉(zhuǎn)換了。 這里你可以這樣理解,相當于把不是父類中含有的函數(shù)從虛擬函數(shù)表中設(shè)置為不可見的。注意有可能虛擬函數(shù)表中有些函數(shù)地址由于在子類中已經(jīng)被改寫了,所以對象虛擬函數(shù)表中虛擬函數(shù)項目地址已經(jīng)被設(shè)置為子類
12、中完成的方法體的地址了。 4、Java與C+多態(tài)性的比較 jvm關(guān)于多態(tài)性支持解決方法是和c+中幾乎一樣的, 只是c+中編譯器很多是把類型信息和虛擬函數(shù)信息都放在一個虛擬函數(shù)表中,但是利用某種技術(shù)來區(qū)別。 Java把類型信息和函數(shù)信息分開放。Java中在繼承以后,子類會重新設(shè)置自己的虛擬函數(shù)表,這個虛擬函數(shù)表中的項目有由兩部分組成。從父類繼承的虛擬函數(shù)和子類自己的虛擬函數(shù)。 虛擬函數(shù)調(diào)用是經(jīng)過虛擬函數(shù)表間接調(diào)用的,所以才得以實現(xiàn)多態(tài)的。 Java的所有函數(shù),除了被聲明為final的,都是用后期綁定。四. 1個行為,不同的對象,他們具體體現(xiàn)出來的方式不一樣, 比如: 方法重載 overloadi
13、ng 以及 方法重寫(覆蓋)override class Human void run()輸出 人在跑 class Man extends Human void run()輸出 男人在跑 這個時候,同是跑,不同的對象,不一樣(這個是方法覆蓋的例子) class Test void out(String str)輸出 str void out(int i)輸出 i 這個例子是方法重載,方法名相同,參數(shù)表不同 ok,明白了這些還不夠,還用人在跑舉例 Human ahuman=new Man(); 這樣我等于實例化了一個Man的對象,并聲明了一個Human的引用,讓它去指向Man這個對象 意思是說,
14、把 Man這個對象當 Human看了. 比如去動物園,你看見了一個動物,不知道它是什么, "這是什么動物? " "這是大熊貓! " 這2句話,就是最好的證明,因為不知道它是大熊貓,但知道它的父類是動物,所以, 這個大熊貓對象,你把它當成其父類 動物看,這樣子合情合理. 這種方式下要注意 new Man();的確實例化了Man對象,所以 ahuman.run()這個方法 輸出的 是 "男人在跑 " 如果在子類 Man下你 寫了一些它獨有的方法 比如 eat(),而Human沒有這個方法, 在調(diào)用eat方法時,一定要注意 強制類型轉(zhuǎn)換 (
15、Man)ahuman).eat(),這樣才可以. 對接口來說,情況是類似的.實例:package domatic; /定義超類superA class superA int i = 100; void fun(int j) j = i; System.out.println("This is superA"); / 定義superA的子類subB class subB extends superA int m = 1; void fun(int aa) System.out.println("This is subB"); / 定義superA的子類su
16、bC class subC extends superA int n = 1; void fun(int cc) System.out.println("This is subC"); class Test public static void main(String args) superA a = new superA(); subB b = new subB(); subC c = new subC(); a = b; a.fun(100); a = c; a.fun(200); /* 上述代碼中subB和subC是超類superA的子類,我們在類Test中聲明了3個
17、引用變量a, b, c,通過將子類對象引用賦值給超類對象引用變量來實現(xiàn)動態(tài)方法調(diào)用。也許有人會問: "為什么(1)和(2)不輸出:This is superA"。 * java的這種機制遵循一個原則:當超類對象引用變量引用子類對象時, * 被引用對象的類型而不是引用變量的類型決定了調(diào)用誰的成員方法, * 但是這個被調(diào)用的方法必須是在超類中定義過的, * 也就是說被子類覆蓋的方法。 * 所以,不要被上例中(1)和(2)所迷惑,雖然寫成a.fun(),但是由于(1)中的a被b賦值, * 指向了子類subB的一個實例,因而(1)所調(diào)用的fun()實際上是子類subB的成員方法fu
18、n(), * 它覆蓋了超類superA的成員方法fun();同樣(2)調(diào)用的是子類subC的成員方法fun()。 * 另外,如果子類繼承的超類是一個抽象類,雖然抽象類不能通過new操作符實例化, * 但是可以創(chuàng)建抽象類的對象引用指向子類對象,以實現(xiàn)運行時多態(tài)性。具體的實現(xiàn)方法同上例。 * 不過,抽象類的子類必須覆蓋實現(xiàn)超類中的所有的抽象方法, * 否則子類必須被abstract修飾符修飾,當然也就不能被實例化了 */ 以上大多數(shù)是以子類覆蓋父類的方法實現(xiàn)多態(tài).下面是另一種實現(xiàn)多態(tài)的方法-重寫父類方法1.JAVA里沒有多繼承,一個類之能有一個父類。而繼承的表現(xiàn)就是多態(tài)。一個父類可以有多個子類,而在子類里可以重寫父類的方法(例如方法print()),這樣每個子類里重寫的代碼不一樣,自然表現(xiàn)形式就不一樣。這樣用父類的變量去引用不同的子類,在調(diào)用這個相同的方法print()的時候得到的結(jié)果和表現(xiàn)形式就不一樣了,這就是多態(tài),相同的消息(也就是調(diào)用相同的方法)會有不同的結(jié)果。舉例說明: /父類 public cla
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 告別虛擬世界重拾現(xiàn)實生活的決心書3篇
- 二手教練車買賣合同3篇
- 云簽約勞動合同電子簽約系統(tǒng)3篇
- 借用合同的擔保義務(wù)免責3篇
- 客服工作心得體會及感悟(30篇)
- 藥廠質(zhì)檢員工作總結(jié)(33篇)
- 工程承包分包條件3篇
- 工程資料承包協(xié)議3篇
- 付款委托書樣本專業(yè)公司3篇
- 建筑施工合同解除與工程保修3篇
- (2025)入團考試題庫及答案
- 掃描電子顯微鏡(SEM)-介紹-原理-結(jié)構(gòu)-應(yīng)用
- 車廂定做合同范文大全
- 《地質(zhì)災(zāi)害監(jiān)測技術(shù)規(guī)范》
- 節(jié)能環(huán)保產(chǎn)品推廣與銷售代理協(xié)議
- 普通地質(zhì)學知到智慧樹章節(jié)測試課后答案2024年秋臨沂大學
- 2024年長安汽車行測筆試題庫
- 2024年度一帶一路貿(mào)易促進與合作合同2篇
- 臨床試驗項目質(zhì)量管理
- 鐵路危險貨物運輸管理企業(yè)運輸員培訓
- 五年(2020-2024)高考語文真題分類匯編專題02 文言文閱讀(原卷版)
評論
0/150
提交評論