JAVA多態(tài)性我與網(wǎng)友交流實(shí)錄(轉(zhuǎn))
發(fā)表時(shí)間:2024-02-14 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]JAVA多態(tài)性<==>我和網(wǎng)友交流實(shí)錄zosatapo(原作) 我在這里公開和我dennisboys的學(xué)習(xí)交流信件,我們主要在談java中多態(tài)性問題。這里感謝我的好朋友能給我一個(gè)結(jié)合自己能力解釋問題的機(jī)會(huì),在解釋中有出錯(cuò)或者需要討論的部分希望能通知我一聲。上篇關(guān)于多態(tài)性的文章請(qǐng)參閱我前...
JAVA多態(tài)性<==>我和網(wǎng)友交流實(shí)錄zosatapo(原作)
我在這里公開和我dennisboys的學(xué)習(xí)交流信件,我們主要在談java中多態(tài)性問題。
這里感謝我的好朋友能給我一個(gè)結(jié)合自己能力解釋問題的機(jī)會(huì),在解釋中有出錯(cuò)
或者需要討論的部分希望能通知我一聲。
上篇關(guān)于多態(tài)性的文章請(qǐng)參閱我前面寫的<<java多態(tài)性實(shí)例解釋一文>>.
*******************************************************************************
網(wǎng)友dennisboys的提問部分開始
*******************************************************************************
從頭到尾把你的代碼看了n次,畫了n個(gè)圖(關(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)用呢?(我試過寫代碼了,果然如你所說是出錯(cuò)的。)
對(duì)于以上的問題,你有一段文字好像是對(duì)其作解譯的。不過我不太清楚。不知是不是以下這
段。
引用原文:
同時(shí)可能有人要問,子類中那個(gè)函數(shù)地址不是也在虛擬函數(shù)表中嗎?
很高興你問這樣的問題,但是父類引用看到的虛擬函數(shù)表是沒有
那個(gè)函數(shù)項(xiàng)目的,因?yàn)樗麑?duì)于父類引用絕對(duì)是不可見。
我現(xiàn)在理解是如果在子類中如對(duì)方法作了更改或新增的方法,對(duì)父類來說是不可見的?理解
對(duì)嗎??
*/
問題二:
((test)b).display();
另一個(gè)迷感就是你說的強(qiáng)制轉(zhuǎn)換類型的語法到底是怎樣的??我不明白為((test)b)代表什么
?
不過說回來(我怎么覺得這個(gè)例子是在說繼承??),這個(gè)例子使我對(duì)繼承有了很深的認(rèn)識(shí)
,我倒是覺得對(duì)多態(tài)性還是一知半解,(別說我笨笨)可能我還沒清楚到底哪用到了多態(tài)性,
不過請(qǐng)先回復(fù)了我以上兩個(gè)問題,希望你回復(fù)了我以上兩個(gè)問題(結(jié)合我研究你的代碼)使我
對(duì)多態(tài)性有更好更深的認(rèn)識(shí)。。
*******************************************************************************
網(wǎng)友dennisboys的提問部分結(jié)束
*******************************************************************************
*******************************************************************************
zosatapo的解釋部分開始
*******************************************************************************
你真的應(yīng)該謝謝我的,因?yàn)槲倚列量嗫啻蛄似恼拢?br>因?yàn)榫W(wǎng)絡(luò)原因沒有能成功保存,害了我重寫一次,
沒有辦法,誰叫你是我的好朋友呢。
首先謝謝你耐心看完我的文章。
下面我就我上次寫的那篇文章和你的問題作簡單的說明但是又比較復(fù)雜的說明。
我上次寫的那篇文章存在一處寫作錯(cuò)誤,我在網(wǎng)上已經(jīng)修正了,這里告訴你一下:
上次的原文中有這樣的幾句話
****************************************
// 下面調(diào)用會(huì)出錯(cuò)的
file://t.display2();
file://應(yīng)該象下面那樣
((test)b).display2();
******************************************
這幾句話寫作上有錯(cuò)誤:
應(yīng)該改成成下面這樣:
**********************************************
// 下面調(diào)用[不]會(huì)出錯(cuò)的(這里多了一個(gè)[不]字)
file://t.display2();
#########################################
實(shí)際上我上面這兩行跟本文沒有關(guān)系的
但是為了你很好的理解動(dòng)態(tài)性,你可以
把上面的代碼與下面的進(jìn)行比較。
#########################################
file://下面這行調(diào)用不會(huì)出錯(cuò)
file://b.display2();這里加了一行
file://應(yīng)該象下面那樣
((test)b).display2();
**********************************************‘
下面正式開始我們今天的話題,正對(duì)你的問題我進(jìn)行解釋,
這里我盡可能的解釋詳細(xì)一點(diǎn)讓你明白,實(shí)際上這里太復(fù)雜
涉及到OOP的具體實(shí)現(xiàn)問題,這個(gè)問題又不得不涉及到編譯器
問題,主要的又是對(duì)象內(nèi)存布局問題。
由于第二個(gè)問題比較簡單,我把回答問題的次序顛倒一下。
*********
問題二
*********
你說的很對(duì),我這里解的是繼承,但是我這里解的不僅僅是繼承的
問題?梢赃@樣是你說的繼承只是我解釋動(dòng)態(tài)性問題的一個(gè)途徑和
手段而已,因?yàn)槔^承和多態(tài)性一樣是面向?qū)ο笾泻苤匾母拍,?br>是寫一點(diǎn)文章就可以說明白的。
簡單一點(diǎn)和不精確的說,動(dòng)態(tài)性與是繼承不可分割的,如果沒有繼承
根本就談不上多態(tài)性的。所以我說你說的對(duì),但是你沒有真正明白我
例子的作用(55555555~~~~~~~~~~~~~我的心血呀)
*********
問題一
*********
首先需要說明的是你對(duì)這個(gè)問題的理解是不正確的。
這個(gè)問題更是復(fù)雜的一塌糊涂,我盡量用一些不標(biāo)準(zhǔn)的詞匯來說明這個(gè)問題。
因?yàn)檫@樣便于理解。我這里不解太多的理論,因?yàn)槲易约含F(xiàn)在也正在研究jvm
規(guī)范的,因?yàn)楹芏鄸|西java和c++不同,雖然兩者實(shí)現(xiàn)很相似。上面這點(diǎn),
我是根據(jù)我個(gè)人的一些實(shí)踐,包括理論方面和程序編寫實(shí)踐得到的。但是
我也不敢全部拿c++的那套實(shí)現(xiàn)講給你聽,實(shí)際上講了你也不一定聽得懂的。
我這里主要講一些基本的知識(shí),你記住就可以了的,等你學(xué)習(xí)深入的時(shí)候
我再給解釋,也許那時(shí)候你自然就懂了。
實(shí)際上在繼承以后,子類會(huì)重新設(shè)置自己的虛擬函數(shù)表,
這個(gè)虛擬函數(shù)表中的項(xiàng)目有由兩部分組成。從父類繼承的虛擬函數(shù)和子類自己
的虛擬函數(shù)。
記住一個(gè)很簡單又很復(fù)雜的規(guī)則,一個(gè)類型引用只能引用引用類型自身含有的
方法和變量。你可能說這個(gè)規(guī)則不對(duì)的,因?yàn)楦割愐弥赶蜃宇悓?duì)象的時(shí)候,
引用是子類的方法的。我告訴你這個(gè)規(guī)則對(duì)于這樣的情況依然是成立的。放松
你的大腦,不要想一些亂七八糟的事情,仔細(xì)聽我分析。
對(duì)了,到這里的時(shí)候我假設(shè)你對(duì)于上面的規(guī)則除了虛擬函數(shù)調(diào)用的情況下,
其他的靜態(tài)函數(shù)引用,以及變量引用都明白了。
下面我們開始我們的重量級(jí)說明。虛擬函數(shù)引用。
下面是jvm規(guī)范中關(guān)于對(duì)象內(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ù)這里我就知道實(shí)際上jvm關(guān)于多態(tài)性支持解決方法是和c++中幾乎一樣的,
只是c++中編譯器很多是把類型信息和虛擬函數(shù)信息都放在一個(gè)虛擬函數(shù)表中,
但是利用某種技術(shù)來區(qū)別。
所以當(dāng)你使用父類引用指向子類的時(shí)候,其實(shí)jvm已經(jīng)使用了編譯器產(chǎn)生的類型
信息調(diào)整轉(zhuǎn)換了。這里你可以這樣理解,相當(dāng)于把不是父類中含有的函數(shù)從虛擬
函數(shù)表中設(shè)置為不可見的。注意有可能虛擬函數(shù)表中有些函數(shù)地址由于在子類中
已經(jīng)被改寫了,所以對(duì)象虛擬函數(shù)表中虛擬函數(shù)項(xiàng)目地址已經(jīng)被設(shè)置為子類中完成
的方法體的地址了。
上面這一段就是為什么父類引用指向子類對(duì)象時(shí)候,有的方法可以調(diào)用,有的方法
卻不能調(diào)用。
虛擬函數(shù)調(diào)用是經(jīng)過虛擬函數(shù)表間接調(diào)用的,所以才得以實(shí)現(xiàn)多態(tài)的。