物件呼叫方法的解析過程

2021-08-21 15:26:55 字數 2357 閱讀 9936

弄清楚如何在物件上應用方法呼叫非常重要。下面假設要呼叫x.f(args),隱式引數x宣告為類c的乙個物件。 下面是呼叫過程的詳細描述:

(1)編譯器檢視物件的宣告型別和方法名。假設呼叫x.f(param),且隱式引數x宣告為c類的物件。 需要注意的是:有可能存在多個名字為f,但引數型別不一樣的方法。 例如可能存在方法f(int)和方法f(string)。編譯器將會一一枚舉所有 c類中名為f的方法和其超類中訪問屬性為public且名為f的方法(超類的私有方法不可訪問)。

至此,編譯器已獲得所有可能被呼叫的候選方法。

(2)接下來,編譯器將檢視呼叫方法時提供的引數型別。如果在所有名為f的方法中存在乙個與提供的引數型別完全匹配,就選擇這個方法。這個過程被稱為過載解析( overloadingresolution)。例如,對於呼叫x.f(「hello」)來說,編譯器將會挑選f(string), 而不是f(int)。 由於允許型別轉換( int可以轉換成double, manager 可以轉換成employee,等等),所以這個過程可能很複雜。如果編譯器沒有找到與引數型別匹配的方法,或者發現經過型別轉換後有多個方法與之匹配,就會報告乙個錯誤。

至此,編譯器已獲得需要呼叫的方法名字和引數型別。

(3)如果是private方法、static 方法、final 方法或者構造器,那麼編譯器將可以準確地知道應該呼叫哪個方法,我們將這種呼叫方式稱為靜態繫結( static binding)。與此對應的是,呼叫的方法依賴於隱式引數的實際型別,井生在執行時實現動態繫結。在我們列舉的示例中,編譯器採用動態繫結的方式生成一條呼叫f(string)的指令。

(4)當程式執行,並且採用動態繫結呼叫方法時,虛擬機器一定呼叫與x所引用物件的實際型別最合適的那個類的方法。假設x的實際型別是d,它是c類的子類。如果d類定義了方法f(string),就直接呼叫它;否則,將在d類的超類中尋找f(string),以此類推。

每次呼叫方法都要進行搜尋,時間開銷相當大。因此,虛擬機器預先為每個類建立了乙個方法表( method table), 其中列出了所有方法的簽名和實際呼叫的方法。這樣一來,在真正呼叫方法的時候,虛擬機器僅查詢這個表就行了。在前面的例子中,虛擬機器搜尋d類的方法表,以便尋找與呼叫f(sting)相匹配的方法。這個方法既有可能是d.f(string),也有可能是x.f(string),這裡的x是d的超類。這裡需要提醒一點, 如果呼叫super.f(param),編譯器將對隱式引數超類的方法表進行搜尋。

呼叫e.getsalay()的詳細過程。e宣告為employee型別。employee類只有一乙個名叫getsalary 的方法,這個方法沒有引數。因此,在這裡不必擔心過載解析的問題。

由於getsalay 不是private方法、static 方法或final 方法,所以將採用動態繫結。虛擬機器為employee和manger兩個類生成方法表。在employee 的方法表中,列出了這個類定義的所有方法。

employee:

getname() -> employee.getname()

getsalary() -> employee.getsalary()

gethireday() -> employee.gethireday()

raisesalary(double) -> employee.raisesalary(double)

manager:

getname() -> employee.getname()

getsalary() -> manager.getsalary()

gethireday() -> employee.gethireday()

raisesalary(double) -> manager.raisesalary(double)

setbonus(double) -> manager.setbonus(double)

在執行時,呼叫e.getsalary()的解析過程為:

(1)首先,虛擬機器提取e的實際型別的方法表。既可能是employee、 manager的方法表,也可能是employee類的其他子類的方法表。

(2)接下來,虛擬機器搜尋定義getsalary簽名的類。此時,虛擬機器已經知道應該呼叫哪個方法。

(3)最後,虛擬機器呼叫方法。

動態繫結有乙個非常重要的特性:無需對現存的**進行修改,就可以對程式進行擴充套件。假設增加乙個新類executive,並且變數e有可能引用這個類的物件,我們不需要對包含呼叫e.getsalary()的**進行重新編譯。如果e恰好引用-乙個executive類的物件,就會自動地呼叫executive. getsalaryo)方法。

警告:在覆蓋乙個方法的時候,子類方法木能低於超類方法的可見性。特別是,如果超類方法是public,子類方法一定要宣告為public。 經常會發生這類錯誤:在宣告子類方法的時候,遺漏了public修飾符。此時,編譯器將會把它解釋為試圖提供更嚴格的訪問許可權。

java 類呼叫方法的解析過程

丁一兩個類 父類employee 列出這個類的所有方法 getname employee.getname getsalary employee.getsalary gethireday hiredate employee.gethireday raiswsalary doubl employee.s...

Python遠端方法呼叫實現過程解析

rpchandler 和 rpcproxy 的基本思路是很比較簡單的。如果乙個客戶端想要呼叫乙個遠端函式,比如 foo 1,2,z 3 類建立乙個包含了函式名和引數的元組 foo 1,2 這個元組被pickle序列化後通過網路連線發生出去。這一步在 rpcproxy 的 getattr 方法返回的 ...

ruby 過程物件 解析

我們總是希望對未知事件分類.當它發生時,向其它方法傳遞一塊作為引數的程式碼是最容易地解決方法,也就是說我們希望像處理資料一樣處理程式碼.乙個新的過程物件可以通過proc建立 ruby quux proc 現在quux指向乙個物件,像其它物件一樣,它也有可以呼叫的行為.特別的,我們可以用call方法執...