自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

從HotSpot虛擬機(jī)源碼了解Java的訪問控制修飾符

云計(jì)算 虛擬化
前面Ribbon源碼分析文章,有讀者留言提問:XX類是包私有的,重寫不會(huì)報(bào)錯(cuò)嗎?答案其實(shí)是XX類并非包私有,而是一個(gè)protected的靜態(tài)內(nèi)部類,所以重寫不會(huì)報(bào)錯(cuò)。

 [[340301]]

前面Ribbon源碼分析文章,有讀者留言提問:XX類是包私有的,重寫不會(huì)報(bào)錯(cuò)嗎?答案其實(shí)是XX類并非包私有,而是一個(gè)protected的靜態(tài)內(nèi)部類,所以重寫不會(huì)報(bào)錯(cuò)。

關(guān)于Java訪問控制修飾符的作用,筆者在初學(xué)Java時(shí)也是靠記,寫多了代碼自然也就能理解,但筆者很好奇底層的實(shí)現(xiàn),所以也嘗試從HotSpot虛擬機(jī)源碼尋找答案,解答我多年來(lái)的疑惑。

類、字段、方法都有哪些訪問控制修飾符?

私有<private>、子類可訪問<protected>、公開public、包私有<package>,默認(rèn)不加訪問控制修飾符就是包私有。

訪問范圍 private package protected public
同一個(gè) 可訪問 可訪問 可訪問 可訪問
同一包中的其他類 不可訪問 可訪問 可訪問 可訪問
不同包中的子類 不可訪問 不可訪問 可訪問 可訪問
不同包中的非子類 不可訪問 不可訪問 不可訪問 可訪問

包私有<package>指的是只有同一個(gè)包下的類可訪問,其它包下的類不可訪問。

今天我們就深入java虛擬機(jī)去探究這些訪問控制修飾符語(yǔ)意的實(shí)現(xiàn)。

InstanceKlass是HotSpot VM中對(duì)應(yīng)class文件結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu),InstanceKlass對(duì)象是一個(gè)Java類被HotSpot VM加載后所生成的C++對(duì)象,被存于方法區(qū)。我們?cè)贘ava代碼中使用的Class對(duì)象實(shí)際是InstanceKlass的一個(gè)鏡像。

Java支持使用"this."、"suppor."、"某個(gè)對(duì)象."調(diào)用一個(gè)方法,或"某個(gè)類."調(diào)用靜態(tài)方法,在我們看來(lái)是調(diào)用某個(gè)類的靜態(tài)方法或者對(duì)象的方法,但這在虛擬機(jī)中并不存在區(qū)別,都是一個(gè)方法調(diào)用。

調(diào)用靜態(tài)方法和對(duì)象方法的區(qū)別只在于,調(diào)用對(duì)象的方法需要在方法參數(shù)傳遞一個(gè)"this"引用,這是一個(gè)隱式參數(shù),在編譯器將Java代碼編譯成字節(jié)碼時(shí)自動(dòng)添加上。

而Java代碼中使用"this."、"suppor."調(diào)用自身方法和父類方法的不同,僅僅只是生成方法調(diào)用字節(jié)碼指令的操作數(shù)指向的Methodref常量不同,方法的第一個(gè)隱式參數(shù)傳遞的對(duì)象都是同一個(gè)。Methodref常量指代一個(gè)方法的符號(hào)引用,包括類名、方法名、方法描述符。

我們知道,類加載過(guò)程包括加載、鏈接、初始化三個(gè)階段,其中鏈接階段又可細(xì)分為驗(yàn)證、準(zhǔn)備和解析三個(gè)階段。下面這張圖有助于我們理解類加載的幾個(gè)階段,但并不準(zhǔn)確。

《Java虛擬機(jī)規(guī)范》只是規(guī)定類加載需要完成的事情,而對(duì)順序并沒有嚴(yán)格的要求。

下圖為筆者閱讀HotSpot虛擬機(jī)類加載源碼總結(jié)出的一張流程圖,僅供參考。(如需要獲取原圖,可在公眾號(hào)回復(fù):"hotspot")

在HotSpot虛擬機(jī)中,鏈接階段的準(zhǔn)備階段在加載階段之后完成,鏈接階段的驗(yàn)證也分多種驗(yàn)證,其中文件格式驗(yàn)證、元數(shù)據(jù)驗(yàn)證在加載階段交叉完成,而字節(jié)碼驗(yàn)證階段則在類初始化之前才觸發(fā),解析階段則在類加載完成之后。

引起類初始化的幾條指令如new、getstatic、putstatic、invokestatic,虛擬機(jī)在執(zhí)行這些指令時(shí),先判斷類是否已經(jīng)初始化,未初始化則完成類的初始化,鏈接階段會(huì)在類初始化階之前觸發(fā)。

鏈接階段的解析階段是Java虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程,根據(jù)《Java虛擬機(jī)規(guī)范》規(guī)定,在ane-warray、checkcast、getfield、getstatic、instanceof、invokedynamic、invokeinterface、invoke-special、invokestatic、invokevirtual、ldc、mulianewarray、new、putfield、putstatic這些要求操作數(shù)指向常量池中的符號(hào)引用常量(如:CONSTANT_Class_info、CONSTANT_Field_info、CONSTANT_Methodref_info)的指令執(zhí)行之前,必須先對(duì)使用的符號(hào)引用進(jìn)行解析。

符號(hào)引用以一組符號(hào)描述引用的目標(biāo),如CONSTANT_Class_info表示引用的類、CONSTANT_Field_info表示引用哪個(gè)類的哪個(gè)字段、CONSTANT_Methodref_info表示引用哪個(gè)類的哪個(gè)方法。

符號(hào)引用驗(yàn)證發(fā)生在解析階段,符號(hào)引用驗(yàn)證包括:通過(guò)字符串描述的全限定名是否能找到對(duì)應(yīng)的類、在指定的類中是否存在簡(jiǎn)單名稱所描述的方法和字段、符號(hào)引用中的類、字段、方法的可訪問性( 、public、 )。

在HotSpot虛擬機(jī)的實(shí)現(xiàn)中,對(duì)于解釋執(zhí)行與動(dòng)態(tài)調(diào)用(invokedynamic),解析階段是在符號(hào)引用將要被使用前才去解析。

方法調(diào)用源碼:javaCalls.cpp; 鏈接解析源碼:linkResolver.cpp;

  1. // 檢查類 
  2. LinkResolver::check_klass_accessability 
  3. // 檢查方法 
  4. LinkResolver::check_method_accessability 
  5. // 檢查字段 
  6. LinkResolver::check_field_accessability 

這些方法調(diào)用最后都調(diào)用Reflection類的對(duì)應(yīng)verify方法完成是否可訪問的判斷,例如Reflection::verify_field_access方法。

Java虛擬機(jī)在解析class文件結(jié)構(gòu)時(shí)、在字節(jié)碼驗(yàn)證階段,也會(huì)對(duì)訪問控制修飾符進(jìn)行驗(yàn)證。

例如,在解析class文件結(jié)構(gòu)時(shí),驗(yàn)證是否能夠繼承父類(Reflection::verify_class_access):

類的訪問修飾符決定了一個(gè)類是否可以被其它類訪問。在解析class文件結(jié)構(gòu)階段,虛擬機(jī)可以驗(yàn)證當(dāng)前類是否能夠繼承父類(父類的訪問控制修飾符決定)、是否能夠?qū)崿F(xiàn)每個(gè)接口(接口的訪問修飾符決定)。

在字節(jié)碼驗(yàn)證階段則驗(yàn)證當(dāng)前類是否可以訪問目標(biāo)類的protected修飾的方法或字段:

在字節(jié)碼驗(yàn)證階段,虛擬機(jī)會(huì)對(duì)類的每個(gè)方法中的每條字節(jié)碼指令都會(huì)進(jìn)行驗(yàn)證,但虛擬機(jī)在字節(jié)碼驗(yàn)證階段,只對(duì)getfield指令做了check_protected驗(yàn)證。可見,字節(jié)碼驗(yàn)證階段沒有做過(guò)多的訪問控制驗(yàn)證。

本文轉(zhuǎn)載自微信公眾號(hào)「 Java藝術(shù)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 Java藝術(shù)公眾號(hào)。

[[340304]]

 

責(zé)任編輯:武曉燕 來(lái)源: Java藝術(shù)
相關(guān)推薦

2009-06-19 10:51:39

Scalapackage訪問修飾符

2009-06-12 13:37:47

訪問權(quán)限修飾符Java教程

2009-08-24 16:49:39

C#修飾符

2021-09-10 00:34:22

Java 線程啟動(dòng)

2009-09-04 11:06:40

C#訪問修飾符

2010-11-05 09:47:11

OracleJava虛擬機(jī)

2009-06-12 14:46:05

static修飾符Java教程

2012-08-06 09:26:19

Java虛擬機(jī)垃圾回收

2015-08-18 09:25:11

Java修飾符關(guān)鍵詞

2011-06-02 14:51:07

JAVA修飾符

2021-11-21 22:36:18

Java修飾符開發(fā)

2009-08-21 13:58:06

C# virtual修

2009-08-27 11:12:03

C# abstract

2009-08-27 13:06:13

C# new修飾符

2023-12-29 09:01:27

SwiftUI視圖修飾符

2009-09-02 17:14:28

C#修飾符

2009-08-27 11:04:08

C# extern修飾

2023-09-25 08:19:37

LinuxVirtualBox虛擬機(jī)

2015-01-06 09:47:55

Java

2009-09-02 17:04:35

C# Extern修飾
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)