日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

疯狂涨知识!Java多态实现原理技术总监都拍手叫好

發(fā)布時間:2023/11/30 java 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 疯狂涨知识!Java多态实现原理技术总监都拍手叫好 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

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

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

程序運(yùn)行時,需要某個類是,類載入系統(tǒng)會將相應(yīng)的class文件載入到JVM中,并在內(nèi)部建立該類的?類型信息 (這個類型信息其實(shí)就是class文件在JVM中存儲的一種數(shù)據(jù)結(jié)構(gòu)),包含java類定義的所有信息(方法代碼、類和成員變量、以及實(shí)現(xiàn)動態(tài)調(diào)用的核心 -?方法表 )。這個類型信息存儲在方法區(qū)。

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

【重點(diǎn)】

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

【拓展】

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

#####Java?的方法調(diào)用方式

Java?的方法調(diào)用有兩類,動態(tài)方法調(diào)用與靜態(tài)方法調(diào)用。

  • 靜態(tài)方法調(diào)用是指對于類的靜態(tài)方法的調(diào)用方式,是靜態(tài)綁定的
  • 動態(tài)方法調(diào)用需要有方法調(diào)用所作用的對象,是動態(tài)綁定的。

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

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

JVM?的方法調(diào)用指令有四個,分別是?invokestatic,invokespecial,invokesvirtual?和?invokeinterface。前兩個是靜態(tài)綁定,后兩個是動態(tài)綁定的。本文也可以說是對于JVM后兩種調(diào)用實(shí)現(xiàn)的考察。

方法表與方法調(diào)用

如有類定義?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() {} }

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

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

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

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

如調(diào)用如下:

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

當(dāng)編譯?Party?類的時候,生成?girl.speak()的方法調(diào)用假設(shè)為:????Invokevirtual #12

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

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

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

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

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

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

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

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

JVM執(zhí)行??Invokevirtual #12?指令的過程:

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

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

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

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

讀者福利

讀到這的朋友還可以免費(fèi)領(lǐng)取一份收集的Java進(jìn)階知識筆記和視頻資料。

資料免費(fèi)領(lǐng)取方式:關(guān)注后,點(diǎn)擊這里即可免費(fèi)領(lǐng)取

更多筆記分享

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

更多筆記分享

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

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

總結(jié)

以上是生活随笔為你收集整理的疯狂涨知识!Java多态实现原理技术总监都拍手叫好的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。