java面向對象經典題目,java虛函數的作用

由於多態需要通過動態綁定才能得以實現,而綁定通俗一點講就是讓不同的對象對同一個函數進行調用,或者反過來講,就是讓同一個函數與不同的對象綁定起來,所以多態得以實現的一個大前提就是,編程語言必須是面向對象的。同時,函數與對象相互綁定,意味着函數也屬於對象的一部分,這便具備了封裝的特性。因為有了封裝,才有了對象。同時,一個函數能夠綁定多個對象,意味着對各不同的對象具有相同的行為,這是繼承的含義。 因此,面向對象的三大特性缺一不可。封裝與繼承其實是為了多態準備的,或者說,封裝與繼承成全了多態,多態讓封裝與繼承的意義最大化。

C++是如何實現多態的

多態的實現,現在幾乎所有的編程語言都是基於虛表實現的,英文vtable。

C++的虛表在哪呢?在new創建的對象的頭部。

虛表裡面存儲的是什麼呢?是虛函數

從hotspot源碼層面剖析Java的多態實現原理

因為hotshot主要是用C++寫的,講了C++的虛表,這張圖你應該就能看懂了。

從hotspot源碼層面剖析Java的多態實現原理

不然總有小夥伴問我:Java的類對應的C++對象,為什麼有C++級別的虛表啊。我沒看到哪裡有這樣的代碼啊。

搞清楚了虛表,再來了解虛表分發就容易多了。虛表分發,其實就是通過虛表內存地址拿到虛表記錄,然後通過函數名+內含參數信息及返回值信息的簽名去虛表中找。因為是從前往後找,所以如果子類重寫了父類的方法,會調用子類的方法。

所以Java雖好,底層也很重要。順便說下,虛表就是用數組實現的,沒有有些小夥伴想得那麼複雜。

JVM中的虛表

JVM的虛表跟C++的虛表還不太一樣。不一樣體現在哪呢?研究虛表研究三個東西:虛表在哪、虛表是用什麼結構實現的、虛表分發機制是怎樣的。JVM的虛表分發等下講,JVM的虛表也是用數組實現的,那這個不一樣就體現在虛表在哪?

Java的類,JVM中對應的C++對象是klass模型。Java的對象,JVM中對應的C++對象是oop模型。C++中的虛表在對象頭中,而JVM的虛表在klass模型的頭部,即Java類對象的頭部。這點區別一定要記住,這樣你才能理解Java對象的內存布局。

問個問題:我們隨便定義的一個類,它有沒有JVM虛表呢?其實是有的。那是哪些方法的內存地址呢?回答這個問題前先得搞明白:什麼樣的方法會存入虛表。只有public、protect類型的,且不被static、final修飾的方法才能被多態調用,才會進入虛表。因為Java中所有的類都是Object的子類,所以Object中滿足這個條件的方法都會在每個類的虛表中。

又到了小夥伴不服氣環節。沒事,上證據。具體怎麼查看我就不講了,有點複雜。對hotspot沒一定的功力講了也沒概念。

從hotspot源碼層面剖析Java的多態實現原理

Java是如何實現虛表分發

JVM實現虛表分發,對應的字節碼指令有兩個:invokevirtual、invokeinterface。上篇文章咱們深入講解了invokeinterface,這篇文章咱們繼續拿這個指令來講這個知識點。我們來看看JVM是如何分發的。其實一看執行invokeinterface時的堆棧,你應該就能明白了。

從hotspot源碼層面剖析Java的多態實現原理

雖然invokeinterface後面的操作數是接口方法信息。但是真正的對象會作為this傳過來。所以在調用的時候,從操作數棧拿到真正的對象,然後通過對象頭中的類型指針拿到TestDuotai對應的C++類對象,即klass模型。前面說了,虛表就在這個對象的頭部。然後通過函數名+內含參數信息及返回值信息的簽名去虛表中找。因為是從前往後找,所以如果子類重寫了父類的方法,會調用子類的方法。這就是JVM虛表分發的底層原理。這塊有點難理解,需要的基礎可能比較深。

從hotspot源碼層面剖析Java的多態實現原理

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/228016.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-09 21:30
下一篇 2024-12-09 21:30

相關推薦

發表回復

登錄後才能評論