JAVA多態(tài)性我與網(wǎng)友交流實錄(轉(zhuǎn))
發(fā)表時間:2024-06-09 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]JAVA多態(tài)性<==>我和網(wǎng)友交流實錄zosatapo(原作) 我在這里公開和我dennisboys的學(xué)習(xí)交流信件,我們主要在談java中多態(tài)性問題。這里感謝我的好朋友能給我一個結(jié)合自己能力解釋問題的機會,在解釋中有出錯或者需要討論的部分希望能通知我一聲。上篇關(guān)于多態(tài)性的文章請參閱我前...
JAVA多態(tài)性<==>我和網(wǎng)友交流實錄zosatapo(原作)
我在這里公開和我dennisboys的學(xué)習(xí)交流信件,我們主要在談java中多態(tài)性問題。
這里感謝我的好朋友能給我一個結(jié)合自己能力解釋問題的機會,在解釋中有出錯
或者需要討論的部分希望能通知我一聲。
上篇關(guān)于多態(tài)性的文章請參閱我前面寫的<<java多態(tài)性實例解釋一文>>.
*******************************************************************************
網(wǎng)友dennisboys的提問部分開始
*******************************************************************************
從頭到尾把你的代碼看了n次,畫了n個圖(關(guān)于父類和子類的函數(shù)地址圖),有以下一些迷惑
test t=new test();
base b=new base();
b=t;
/*
問題一:
這里是把父類的引用指向子類,那是不是說調(diào)用父類的方法就等于調(diào)用子類的方法呢?就是
如果b.display2()不是調(diào)用子類的display2()方法嗎?而子類有display2()方法,為什么不能
調(diào)用呢?(我試過寫代碼了,果然如你所說是出錯的。)
對于以上的問題,你有一段文字好像是對其作解譯的。不過我不太清楚。不知是不是以下這
段。
引用原文:
同時可能有人要問,子類中那個函數(shù)地址不是也在虛擬函數(shù)表中嗎?
很高興你問這樣的問題,但是父類引用看到的虛擬函數(shù)表是沒有
那個函數(shù)項目的,因為他對于父類引用絕對是不可見。
我現(xiàn)在理解是如果在子類中如對方法作了更改或新增的方法,對父類來說是不可見的?理解
對嗎??
*/
問題二:
((test)b).display();
另一個迷感就是你說的強制轉(zhuǎn)換類型的語法到底是怎樣的??我不明白為((test)b)代表什么
?
不過說回來(我怎么覺得這個例子是在說繼承??),這個例子使我對繼承有了很深的認識
,我倒是覺得對多態(tài)性還是一知半解,(別說我笨笨)可能我還沒清楚到底哪用到了多態(tài)性,
不過請先回復(fù)了我以上兩個問題,希望你回復(fù)了我以上兩個問題(結(jié)合我研究你的代碼)使我
對多態(tài)性有更好更深的認識。。
*******************************************************************************
網(wǎng)友dennisboys的提問部分結(jié)束
*******************************************************************************
*******************************************************************************
zosatapo的解釋部分開始
*******************************************************************************
你真的應(yīng)該謝謝我的,因為我辛辛苦苦打了篇文章,
因為網(wǎng)絡(luò)原因沒有能成功保存,害了我重寫一次,
沒有辦法,誰叫你是我的好朋友呢。
首先謝謝你耐心看完我的文章。
下面我就我上次寫的那篇文章和你的問題作簡單的說明但是又比較復(fù)雜的說明。
我上次寫的那篇文章存在一處寫作錯誤,我在網(wǎng)上已經(jīng)修正了,這里告訴你一下:
上次的原文中有這樣的幾句話
****************************************
// 下面調(diào)用會出錯的
file://t.display2();
file://應(yīng)該象下面那樣
((test)b).display2();
******************************************
這幾句話寫作上有錯誤:
應(yīng)該改成成下面這樣:
**********************************************
// 下面調(diào)用[不]會出錯的(這里多了一個[不]字)
file://t.display2();
#########################################
實際上我上面這兩行跟本文沒有關(guān)系的
但是為了你很好的理解動態(tài)性,你可以
把上面的代碼與下面的進行比較。
#########################################
file://下面這行調(diào)用不會出錯
file://b.display2();這里加了一行
file://應(yīng)該象下面那樣
((test)b).display2();
**********************************************‘
下面正式開始我們今天的話題,正對你的問題我進行解釋,
這里我盡可能的解釋詳細一點讓你明白,實際上這里太復(fù)雜
涉及到OOP的具體實現(xiàn)問題,這個問題又不得不涉及到編譯器
問題,主要的又是對象內(nèi)存布局問題。
由于第二個問題比較簡單,我把回答問題的次序顛倒一下。
*********
問題二
*********
你說的很對,我這里解的是繼承,但是我這里解的不僅僅是繼承的
問題。可以這樣是你說的繼承只是我解釋動態(tài)性問題的一個途徑和
手段而已,因為繼承和多態(tài)性一樣是面向?qū)ο笾泻苤匾母拍睿?br>是寫一點文章就可以說明白的。
簡單一點和不精確的說,動態(tài)性與是繼承不可分割的,如果沒有繼承
根本就談不上多態(tài)性的。所以我說你說的對,但是你沒有真正明白我
例子的作用(55555555~~~~~~~~~~~~~我的心血呀)
*********
問題一
*********
首先需要說明的是你對這個問題的理解是不正確的。
這個問題更是復(fù)雜的一塌糊涂,我盡量用一些不標準的詞匯來說明這個問題。
因為這樣便于理解。我這里不解太多的理論,因為我自己現(xiàn)在也正在研究jvm
規(guī)范的,因為很多東西java和c++不同,雖然兩者實現(xiàn)很相似。上面這點,
我是根據(jù)我個人的一些實踐,包括理論方面和程序編寫實踐得到的。但是
我也不敢全部拿c++的那套實現(xiàn)講給你聽,實際上講了你也不一定聽得懂的。
我這里主要講一些基本的知識,你記住就可以了的,等你學(xué)習(xí)深入的時候
我再給解釋,也許那時候你自然就懂了。
實際上在繼承以后,子類會重新設(shè)置自己的虛擬函數(shù)表,
這個虛擬函數(shù)表中的項目有由兩部分組成。從父類繼承的虛擬函數(shù)和子類自己
的虛擬函數(shù)。
記住一個很簡單又很復(fù)雜的規(guī)則,一個類型引用只能引用引用類型自身含有的
方法和變量。你可能說這個規(guī)則不對的,因為父類引用指向子類對象的時候,
引用是子類的方法的。我告訴你這個規(guī)則對于這樣的情況依然是成立的。放松
你的大腦,不要想一些亂七八糟的事情,仔細聽我分析。
對了,到這里的時候我假設(shè)你對于上面的規(guī)則除了虛擬函數(shù)調(diào)用的情況下,
其他的靜態(tài)函數(shù)引用,以及變量引用都明白了。
下面我們開始我們的重量級說明。虛擬函數(shù)引用。
下面是jvm規(guī)范中關(guān)于對象內(nèi)存布局的說明,我沒有翻譯
我想你可以看明白,反正我現(xiàn)在看英文沒有問題,
如果不明白就查字典。
The Java Virtual Machine does not require any particular internal
structure for objects. In Sun's current implementation of the Java
Virtual Machine, a reference to a class instance is a pointer
to a handle that is itself a pair of pointers: one to a table
containing the methods of the object and a pointer to the
Class object that represents the type of the object, and
the other to the memory allocated from the Java heap for
the object data.
根據(jù)這里我就知道實際上jvm關(guān)于多態(tài)性支持解決方法是和c++中幾乎一樣的,
只是c++中編譯器很多是把類型信息和虛擬函數(shù)信息都放在一個虛擬函數(shù)表中,
但是利用某種技術(shù)來區(qū)別。
所以當(dāng)你使用父類引用指向子類的時候,其實jvm已經(jīng)使用了編譯器產(chǎn)生的類型
信息調(diào)整轉(zhuǎn)換了。這里你可以這樣理解,相當(dāng)于把不是父類中含有的函數(shù)從虛擬
函數(shù)表中設(shè)置為不可見的。注意有可能虛擬函數(shù)表中有些函數(shù)地址由于在子類中
已經(jīng)被改寫了,所以對象虛擬函數(shù)表中虛擬函數(shù)項目地址已經(jīng)被設(shè)置為子類中完成
的方法體的地址了。
上面這一段就是為什么父類引用指向子類對象時候,有的方法可以調(diào)用,有的方法
卻不能調(diào)用。
虛擬函數(shù)調(diào)用是經(jīng)過虛擬函數(shù)表間接調(diào)用的,所以才得以實現(xiàn)多態(tài)的。