JAVA多型性<==>我和網友交流實錄 (轉)

worldblog發表於2007-12-12
JAVA多型性<==>我和網友交流實錄 (轉)[@more@]

我在這裡公開和我dennisboys的學習交流信件,我們主要在談中多型性問題。
這裡感謝我的好朋友能給我一個結合自己能力解釋問題的機會,在解釋中有出錯
或者需要討論的部分希望能通知我一聲。


上篇關於多型性的文章請參閱我前面寫的<>.



*******************************************************************************
 網友dennisboys的提問部分開始
*******************************************************************************
從頭到尾把你的程式碼看了n次,畫了n個圖(關於父類和子類的地址圖),有以下一些迷惑
test t=new test();
base b=new base();
b=t;


/*
問題一:
這裡是把父類的引用指向子類,那是不是說父類的方法就等於呼叫子類的方法呢?就是
如果b.display2()不是呼叫子類的display2()方法嗎?而子類有display2()方法,為什麼不能
呼叫呢?(我試過寫程式碼了,果然如你所說是出錯的。)


對於以上的問題,你有一段文字好像是對其作解譯的。不過我不太清楚。不知是不是以下這
段。


引用原文:
同時可能有人要問,子類中那個函式地址不是也在虛擬函式表中嗎?
很高興你問這樣的問題,但是父類引用看到的虛擬函式表是沒有
那個函式專案的,因為他對於父類引用絕對是不可見。


我現在理解是如果在子類中如對方法作了更改或新增的方法,對父類來說是不可見的?理解
對嗎??
*/


問題二:
((test)b).display();
另一個迷感就是你說的強制轉換型別的語法到底是怎樣的??我不明白為((test)b)代表什麼


不過說回來(我怎麼覺得這個例子是在說繼承??),這個例子使我對繼承有了很深的認識
,我倒是覺得對多型性還是一知半解,(別說我笨笨)可能我還沒清楚到底哪用到了多型性,
不過請先回復了我以上兩個問題,希望你回覆了我以上兩個問題(結合我研究你的程式碼)使我
對多型性有更好更深的認識。。
*******************************************************************************
 網友dennisboys的提問部分結束
*******************************************************************************



*******************************************************************************
 zosatapo的解釋部分開始
*******************************************************************************


你真的應該謝謝我的,因為我辛辛苦苦打了篇文章,
因為原因沒有能成功儲存,害了我重寫一次,
沒有辦法,誰叫你是我的好朋友呢。


首先謝謝你耐心看完我的文章。


下面我就我上次寫的那篇文章和你的問題作簡單的說明但是又比較複雜的說明。


我上次寫的那篇文章存在一處寫作錯誤,我在網上已經修正了,這裡告訴你一下:


上次的原文中有這樣的幾句話
****************************************
 // 下面呼叫會出錯的
 ();
 該象下面那樣
 ((test)b).display2();
******************************************


這幾句話寫作上有錯誤:
應該改成成下面這樣:


**********************************************
 // 下面呼叫[不]會出錯的  (這裡多了一個[不]字)
 (); 
######################################### 
 實際上我上面這兩行跟本文沒有關係的
 但是為了你很好的理解動態性,你可以
 把上面的程式碼與下面的進行比較。
#########################################
 面這行呼叫不會出錯
 ();  這裡加了一行
 該象下面那樣
 ((test)b).display2();
**********************************************‘



下面正式開始我們今天的話題,正對你的問題我進行解釋,
這裡我儘可能的解釋詳細一點讓你明白,實際上這裡太複雜
涉及到的具體實現問題,這個問題又不得不涉及到
問題,主要的又是佈局問題。


由於第二個問題比較簡單,我把回答問題的次序顛倒一下。


*********
  問題二
*********
你說的很對,我這裡解的是繼承,但是我這裡解的不僅僅是繼承的
問題。可以這樣是你說的繼承只是我解釋動態性問題的一個途徑和
手段而已,因為繼承和多型性一樣是物件導向中很重要的概念,不
是寫一點文章就可以說明白的。


簡單一點和不精確的說,動態性與是繼承不可分割的,如果沒有繼承
根本就談不上多型性的。所以我說你說的對,但是你沒有真正明白我
例子的作用(55555555~~~~~~~~~~~~~我的心血呀)


*********
  問題一
*********
首先需要說明的是你對這個問題的理解是不正確的。


這個問題更是複雜的一塌糊塗,我儘量用一些不標準的詞彙來說明這個問題。
因為這樣便於理解。我這裡不解太多的理論,因為我自己現在也正在研究jvm
規範的,因為很多東西java和c++不同,雖然兩者實現很相似。上面這點,
我是根據我個人的一些實踐,包括理論方面和編寫實踐得到的。但是
我也不敢全部拿c++的那套實現講給你聽,實際上講了你也不一定聽得懂的。
我這裡主要講一些基本的知識,你記住就可以了的,等你學習深入的時候
我再給解釋,也許那時候你自然就懂了。
實際上在繼承以後,子類會重新設定自己的虛擬函式表,
這個虛擬函式表中的專案有由兩部分組成。從父類繼承的虛擬函式和子類自己
的虛擬函式。


記住一個很簡單又很複雜的規則,一個型別引用只能引用引用型別自身含有的
方法和變數。你可能說這個規則不對的,因為父類引用指向子類物件的時候,
引用是子類的方法的。我告訴你這個規則對於這樣的情況依然是成立的。放鬆
你的大腦,不要想一些亂七八糟的事情,仔細聽我分析。


對了,到這裡的時候我假設你對於上面的規則除了虛擬函式呼叫的情況下,
其他的靜態函式引用,以及變數引用都明白了。


下面我們開始我們的重量級說明。虛擬函式引用。
下面是jvm規範中關於物件記憶體佈局的說明,我沒有翻譯
我想你可以看明白,反正我現在看英文沒有問題,
如果不明白就查字典。
The Java Virtual Machine does not require any particular internal
structure for s. 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.


根據這裡我就知道實際上jvm關於多型性支援解決方法是和c++中幾乎一樣的,
只是c++中編譯器很多是把型別資訊和虛擬函式資訊都放在一個虛擬函式表中,
但是利用某種技術來區別。


所以當你使用父類引用指向子類的時候,其實jvm已經使用了編譯器產生的型別
資訊調整轉換了。這裡你可以這樣理解,相當於把不是父類中含有的函式從虛擬
函式表中設定為不可見的。注意有可能虛擬函式表中有些函式地址由於在子類中
已經被改寫了,所以物件虛擬函式表中虛擬函式專案地址已經被設定為子類中完成
的方法體的地址了。


上面這一段就是為什麼父類引用指向子類物件時候,有的方法可以呼叫,有的方法
卻不能呼叫。


虛擬函式呼叫是經過虛擬函式表間接呼叫的,所以才得以實現多型的。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992124/,如需轉載,請註明出處,否則將追究法律責任。

相關文章