瘋狂漲知識!Java多態實現原理技術總監都拍手叫好

##前言
多態是Java語言重要的特性之一,它允許基類的指針或引用指向派生類的對象,而在具體訪問時實現方法的動態綁定。Java對于方法調用動態綁定的實現主要依賴于方法表,但通過引用調用(invokevitual)和接口引用調用(invokeinterface)的實現則有所不同。

Java多態實現原理的大致過程:首先是Java編譯器將Java源代碼編譯成class文件。在編譯過程中,會根據靜態類型將調用的符號引用寫到class文件中。在執行時,JVM根據class文件找到調用方法的符號引用,然后在靜態類型的方法表中找到偏移量,然后再根據this指針確定對象的實際類型,使用實際類型的方法表(偏移量跟靜態類型中的偏移量一樣是指?就是用的靜態類型中的偏移量,因為符號引用在靜態類型的方法表中找到的偏移量是同一個),如果在實際的方法中找到該方法(說明參數值對上了)則直接調用,否則認為沒有重寫父類的方法則按照繼承關系從下往上搜索來調用方法。

image

程序運行時,需要某個類是,類載入系統會將相應的class文件載入到JVM中,并在內部建立該類的?類型信息 (這個類型信息其實就是class文件在JVM中存儲的一種數據結構),包含java類定義的所有信息(方法代碼、類和成員變量、以及實現動態調用的核心 -?方法表 )。這個類型信息存儲在方法區。

注意:這個方法去中的類型信息跟在堆中存放的class對象是不同的。在方法區中,這個class的類型信息只有唯一的實例(所以是各個線程共享的內存區域),而在堆中可以有多個該class對象。可以通過堆中的class對象訪問到方法去中的類型信息(像Java的反射機制,通過class對象可以訪問到該類的所有信息)。

【重點】

方法表是實現動態調用的核心。上面講過方法表存放在方法區中的類型信息中。為了優化對象調用方法的速度,方法區的類型信息會增加一個指針,該指針指向一個記錄該類方法的方法表,方法表中的每一個項都是對應方法的指針。
這些方法中包括從父類繼承的所有方法以及自身重寫(override)的方法。

【拓展】

方法區:方法區和JAVA堆一樣,是各個線程共享的內存區域,用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。?
運行時常量池:它是方法區的一部分,Class文件中除了有類的版本、方法、字段等描述信息外,還有一項信息是常量池,用于存放編譯器生成的各種符號引用,這部分信息在類加載時進入方法區的運行時常量池中。?
方法區的內存回收目標是針對常量池的回收及對類型的卸載。

#####Java?的方法調用方式

Java?的方法調用有兩類,動態方法調用與靜態方法調用。

  • 靜態方法調用是指對于類的靜態方法的調用方式,是靜態綁定的
  • 動態方法調用需要有方法調用所作用的對象,是動態綁定的。

類調用?(invokestatic)?是在編譯時就已經確定好具體調用方法的情況。

實例調用?(invokevirtual)則是在調用的時候才確定具體的調用方法,這就是動態綁定,也是多態要解決的核心問題。

JVM?的方法調用指令有四個,分別是?invokestatic,invokespecial,invokesvirtual?和?invokeinterface。前兩個是靜態綁定,后兩個是動態綁定的。本文也可以說是對于JVM后兩種調用實現的考察。

方法表與方法調用

如有類定義?Person, Girl, Boy

class Person {public String toString() {return "I'm a person.";}public void eat() {}public void speak() {}
}class Boy extends Person {public String toString() {return "I'm a boy";}public void speak() {}public void fight() {}
}class Girl extends Person {public String toString() {return "I'm a girl";}public void speak() {}public void sing() {}
}

當這三個類被載入到?Java?虛擬機之后,方法區中就包含了各自的類的信息。Girl?和?Boy?在方法區中的方法表可表示如下:

可以看到,Girl?和?Boy?的方法表包含繼承自 Object 的方法,繼承自直接父類 Person 的方法及各自新定義的方法。注意方法表條目指向的具體的方法地址,如?Girl?繼承自?Object?的方法中,只有?toString()?指向自己的實現(Girl?的方法代碼),其余皆指向?Object?的方法代碼;其繼承自于?Person?的方法?eat()?和?speak()?分別指向?Person?的方法實現和本身的實現。

如果子類改寫了父類的方法,那么子類和父類的那些同名的方法共享一個方法表項。

因此,方法表的偏移量總是固定的。所有繼承父類的子類的方法表中,其父類所定義的方法的偏移量也總是一個定值。
Person?或?Object中的任意一個方法,在它們的方法表和其子類?Girl?和?Boy?的方法表中的位置 (index) 是一樣的。這樣?JVM?在調用實例方法其實只需要指定調用方法表中的第幾個方法即可。

如調用如下:

class Party {void happyHour() {Person girl = new Girl();girl.speak();}
}

當編譯?Party?類的時候,生成?girl.speak()的方法調用假設為:????Invokevirtual #12

設該調用代碼對應著?girl.speak(); #12?是?Party?類的常量池的索引。JVM?執行該調用指令的過程如下所示:

(這里有個錯誤,上圖為ClassReference常量池而非Party的常量池)
【再次拓展】

常量池在邏輯上可以分成多個表,每個表包含一類的常量信息,本文只探討對于 Java 調用相關的常量池表。

CONSTATNT_Method_info**:**類方法引用表;包含引用的任何類型方法的描述信息,主要包括類信息索引和名字類型索引。

CONSTATNT_Class_info**:**類信息表;包含任何被引用的類或接口的 ‘符號引用’ ,每一個條目主要包含一個索引,指向CONSTA_Utf8_info表,表示該類或接口的全限定名。

CONSTATNT_NameAndType_info:名字類型表;包含引用的任意方法或字段的名稱和描述符信息在字符串常量中的索引。

CONSTATNT_Utf8_info:字符串常量表; 該表包含該類所使用的所有字符串常量,比如代碼中的字符串引用、引用的類名、方法的名字、其他引用的類與方法的字符串描述等等。其余常量池表中所涉及到的任何常量字符串都被索引至該表。

可以看到,給定任意一個方法的索引,在常量池中找到對應的條目后,可以得到該方法的類索引(classindex)和名字類型索引 (nameandtypeindex), 進而得到該方法所屬的類型信息和名稱及描述符信息(參數,返回值等)——從而通過對方法的類型信息和名稱及描述符信息(參數,返回值等)來確定具體是調用哪一個方法。

JVM執行??Invokevirtual #12?指令的過程:

(1)在常量池中找到方法調用的符號引用。?JVM 首先查看 Party(應為ClassReference常量池) 的常量池索引為 12 的條目 (此條目即指 -?查看常量池中的CONSTATNT_Method_info表,即類方法引用表),再 進一步查看常量池中的(CONSTANTClassinfo,CONSTANTNameAndTypeinfo ,CONSTANTUtf8info)?三個表。

(2) 可得出要調用的方法是 Person 的 speak 方法, 查看 Person 的方法表,得出 speak 方法在該方法表中的偏移量 15,這就是該方法調用的直接引用。

(3)?根據this指針得到具體的對象(即girl所指向位與堆中的對象)

(4)根據對象得到該對象對應的方法表,根據偏移量15查看有無重寫(override)該方法,如果重寫,則可以直接調用(Girl的方法表的speak項指向自身的方法而非父類);如果沒有重寫,則需要拿到按照繼承關系從下往上的基類(這里是Person類)的方法表,同樣按照這個偏移量15查看有無該方法。
##最后
以上,是對Java多態實現原理翻閱兩篇博文后為便于理解而整理而出。
參考博文:
https://www.cnblogs.com/kaleidoscope/p/9790766.html
https://zhuanlan.zhihu.com/p/94086109
大家看完有什么不懂的可以在下方留言討論.
謝謝你的觀看。

讀者福利

讀到這的朋友還可以免費領取一份收集的Java進階知識筆記和視頻資料。

資料免費領取方式:關注后,點擊這里即可免費領取

秋招我借這份PDF的復習思路,收獲美團,小米,京東等Java崗offer

更多筆記分享

秋招我借這份PDF的復習思路,收獲美團,小米,京東等Java崗offer

秋招我借這份PDF的復習思路,收獲美團,小米,京東等Java崗offer

[外鏈圖片轉存中…(img-RDB9BwcB-1623502351596)]

更多筆記分享

[外鏈圖片轉存中…(img-dSYh4L64-1623502351597)]

[外鏈圖片轉存中…(img-pDxH0Vjj-1623502351598)]

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386082.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386082.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386082.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

國內互聯網公司算法機器學習崗(阿里星)面試總結

從2015年8月到2015年10月,花了3個月時間找工作,先后通過內推參加了美團、阿里螞蟻金服、京東、騰訊、今日頭條、Growing IO、微軟這7個公司的面試,同時參加了網易游戲、LinkedI In中國這2個公司的筆試,拿到比較優質的offer是京東S…

瘋狂漲知識!「高并發秒殺」微信搶紅包實戰案例幫你突破瓶頸

推薦閱讀: 阿里二面涼經:設計模式緩存Spring虛擬機MySQL中間件并發等難題,全部迎刃而解阿里巴巴字節跳動那些大廠必問的HTTP該怎么學?我建議你看看這篇文章!螞蟻、字節、PDD社招面經Java崗(分布式線程安全…

2016面試——騰訊、螞蟻金服、蘑菇街

騰訊TST技術面: 先羅列一下問題吧: 編程語言編譯的過程 同樣的邏輯,golang的二進制代碼比C語言的二進制代碼長很多.試分析原因 項目 ,三個項目都有聊.因為現場面,可以用紙寫,所以描述的更清楚些 N * N的方格紙,里面有多少個正方形 兩個數組求交集 什么樣的…

Android開發;Activity-Hook你了解多少?一起來debug

享學課堂特邀作者:周周 轉載請聲明出處! 前言 手把手講解系列文章,是我寫給各位看官,也是寫給我自己的。文章可能過分詳細,但是這是為了幫助到盡量多的人,畢竟工作5,6年,不能老吸血,…

牛客網筆記之JAVA運算符

計算機的最基本用途之一就是執行數學運算,作為一門計算機語言,Java也提供了一套豐富的運算符來操縱變量。我們可以把運算符分成以下幾組: 算術運算符 關系運算符 位運算符 邏輯運算符 賦值運算符 其他運算符 邏輯運算符結果 ~a是按位非&#…

Android架構師談:View-Pager-性能優化之-無限循環

作者:享學課堂Alvin老師 轉載請聲明出處! ViewPager實現無限滑動 **方案一:**將viewpager上限設置成一個很大的數,第一個頁面設置到中間。然后滑動的時候,用當前的序號與viewpager頁面數取余得到目標頁面的序號&#…

你知道如何用面向對象思想寫好并發編程嗎?

在工作中,我發現很多人在設計之初都是直接按照單線程的思路來寫程序的,而忽略了本應該重視的并發問題;等上線后的某天,突然發現詭異的 Bug,再歷經千辛萬苦終于定位到問題所在,卻發現對于如何解決已經沒有了…

你知道怎么在生產環境下部署tomcat嗎?

享學課堂特邀作者:老顧 轉載請聲明出處! 一、前言 小伙伴們在網上看到的很多文章,都是對tomcat的一些介紹,什么配置啊,怎么啟動。其實在生產環境中怎么部署,和網上介紹的有很大區別。這篇文章老顧就帶著大…

淺談HashMap

Java集合類的整體架構 比較重要的集合類圖如下: 有序否 允許元素重復否 Collection 否 是 List 是 是 Set AbstractSet 否 否 HashSet TreeSet 是(用二叉樹排序) Map AbstractMap 否 使用 key-value 來映射和存儲數據, Key 必須惟…

matlab實現一元線性回歸和多元線性回歸

在回歸分析中,如果有兩個或兩個以上的自變量,就稱為多元回歸。事實上,一種現象常常是與多個因素相聯系的,由多個自變量的最優組合共同來預測或估計因變量,比只用一個自變量進行預測或估計更有效,更符合實際。 在實際經濟問題中,一個變量往往受到多個變量的影響。例如,家…

互聯網寒冬!“996”為什么還沒實行?我還等著早點下班呢!

“喊了十多個月的‘996’,說要實行‘996’,上班上到現在,影子都沒看到,我還能早點下班嗎?” 我一個在廣州上班的朋友小李,在我去廣州出差期間,與他聊天的時候發出了這樣的牢騷,我剛…

matlab求解常微分方程組/傳染病模型并繪制SIR曲線

看了很多關于傳染病模型的matlab程序,大都是繪制出兩條曲線(I、S)的,本文最大的不同是繪出SIR三條曲線。 先給出SIR微分方程組 函數文件: run的程序:

互聯網寒冬!技術站最全MySQL數據庫實戰規范

享學課堂特邀作者:老顧 轉載請聲明出處! 前言 我們小伙伴們經常使用到mysql數據庫,一般就這么一用,很少會考慮mysql里面的細節問題,如sql語句的規范,或索引有沒有起到相應的效果,今天老顧就給大…

SQL求一個表中非重復數據及其出現的次數

mysql中,我們可以用distinct求不重復的數據有多少,也可以用group by。 這里有個例子,如下表sheet1,共有5411條數據 查詢語句 共有3446條不重復數據,每條不重復數據出現的次數在第二列顯示:

什么是微服務擴展性和高可用-可擴展性、高可用性和性能

歡迎關注專欄:Java架構技術進階。里面有大量batj面試題集錦,還有各種技術分享,如有好文章也歡迎投稿哦。 Overview 可擴展性、高可用性和性能 術語可擴展性、高可用性、性能和關鍵任務對于不同的組織或組織內的不同部門來說可能意味著不同的…

SQL實現當前行等于前面兩行數據之和

sql實現類似斐波那契數列的功能,即當前數據等于前面兩個數據之和,詳看本文例子 原表: sql語句(此處要熟悉JION ON的用法) 結果

【大牛系列教學】靠著這份面試題跟答案

開篇閑扯 打工人,打工魂,我們生而人上人。當“資本主義”逐漸禁錮我們人(大)上(韭)人(菜)肉體的時候,那一刻我才明白那個日不落帝國資本主義收割機瑞民族之光幸瑞幸咖啡…

matlab實現二項分布

二項分布 1. 求n次獨立重復試驗中事件A恰好發生k次的概率P。 命令:pdf 或 binopdf 格式:pdf (‘bino’, k, n, p) 或 binopdf (k, n, p) 說明:該命令的功能是計算二項分布中事件A恰好發生k次的概率。pdf為通用函數,bino表示二項分布,binopdf為專用函數,n為試驗總次數,…

【工作感悟】成功入職阿里月薪45K

前言 苦苦尋覓找工作之間,殊不知今日之時乃我心之痛,難道是我不配擁有工作嘛。自面試后他所謂的等待都過去一段時日,可惜在下京東上的小金庫都要見低啦。每每想到不由心中一緊。正處為難之間,手機忽然來了個短信預約后續面試。 我…

Mysql優化技巧

索引優化,查詢優化,查詢緩存,服務器設置優化,操作系統和硬件優化,應用層面優化(web服務器,緩存)等等。這里的記錄的優化技巧更適用于開發人員,都是從網絡上收集和自己整理…