【JVM虛擬機】(6)---深入理解Class中訪問標志、類索引、父類索引、接口索引


JVM(6)訪問標志,類索引

上一篇博客講【JVM虛擬機】(5)---深入理解JVM-Class中常量池

我們知道一個class文件正常可以分為7個部分:

  • 魔數與class文件版本
  • 常量池
  • 訪問標志
  • 類索引、父類索引、接口索引
  • 字段表集合
  • 方法表集合
  • 屬性表集合

那么這篇博客主要講有關 訪問標志類索引、父類索引、接口索引 相關的理解和代碼示例。

先通俗的說下這兩個的作用:

訪問標志: 告知該類是一個什么類型的類,是普通類?還是接口?還是枚舉?或者其它類,是用什么修飾符修飾該類的。

類索引、父類索引、接口索引: 告知該類全限名的常量池地址,有繼承的話父類全限名的常量池地址,實現接口的話接口全限名的常量池地址(接口可以多個)。

一、概述

先對上篇博客做個補充:上篇博客雖然說了常量池但對class整體文件結構並沒有說清楚,其實一個class文件即

.class 文件本質上就是一張,由下表所示的數據項構成。

上圖也就是一開始所講的7個部分組成。


二、訪問標志

有關訪問標志找了很多資料,也看了《深入了解java虛擬機》書中第六章給的有關訪問標志的信息,網上幾乎講訪問標志都是下面這張圖,然后寫個pulic class 類 一測試,果然是0021 代表 ACC_PUBLIC+ACC_SUPER 這樣一看是沒毛病。但是都沒有再寫一個接口來驗證的,如果自己寫個接口就會發現下面我圈紅的地方說,JDK1.2后該處必須為真 是不對的。先看圖。

1、訪問標志轉為16進制解釋

思考:就好比為什么ACC_PUBLIC是00 01?如何產生的呢。

訪問標志實際上就是一系列組合,因為有16位所以共有16個標志可以使用,但是目前就定義了8個,剩下的估計是給jdk9和10......預留的吧。這8個如圖所示。

講完理論,接下來我們進行代碼測試,為了校驗更佳准確我寫個普通類和接口分別測試:

2、public class修飾類

public class XiaoXiao {
  
}

在同一目錄生成成class文件

javac XiaoXiao.java

在看反編譯class文件

javap -v XiaoXiao.class

我們發現這里flags為: ACC_PUBLIC, ACC_SUPER,那這么推算那么十六進制應該是0021。

那我們再來查看XiaoXiao.class的十六進制數據

完美吻合。

3、接口校驗

public interface DaDa {

}

同樣先生成class文件在反編譯class文件

看圖我們可以發現flags值為:ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT ,這個也很好理解接口本身就是抽象類。那么加起來就是0601。但這里和上圖有點不符的地方就是圖中說ACC_SUPER只要是JDK1.2必須為真,而這里明顯不為真,所以有關這點並不准確。

那我們再將class文件轉位16進制驗證。

這么一來驗證也是通過的。

有關ACC_SUPER不准確的問題,應該是ACC_SUPER不會是在JDK1.2以后必須為真,應該如下描述:


三、類索引、父類索引、接口索引

1、概念

在 .class 文件中由這三項數據來確定這個的繼承關系。

1、類索引:u2 數據類型,用於確定這個類的全限定名。

2、父類索引:u2 數據類型,用於確定這個類的父類的全限定名。

3、接口索引:u2 數據類型的集合,用於描述類實現了哪些接口,這些被實現的接口將按照 implements 語句后的順序從左至右排列在接口索引集合中。

接口索引集合分為兩部分,第一部分表示接口計數器(interfaces_count),是一個 u2 類型的數據,第二部分是接口索引表表示接口信息,緊跟在接口計數器之后。

若一個類實現的接口為 0,則接口計數器的值為 0,接口索引表不占用任何字節。

同樣這里測試寫兩個測試類來測試。

1、普通類測試

public class XiaoXiao {
  
}

同樣生成class文件,然后查看16進制數據

我們看到該類的類索引在常量池0002位置 ,父類索引在常量池0003位置,接口為0000代表該類沒有實現任何接口。

然后我們在反編譯XiaoXiao.class文件,方便我們查找常量池。

真的是一目了然,常量池0002就是當前類,0003父類為默認繼承了老祖宗Object。

完美!

2、實現接口測試

為了更加深刻理解,這里再寫一個類實現兩個接口的類,在來查看。

//接口
public interface DaDa { 
}
//接口
public interface LaLa {
}
//類實現上面兩個接口
public class XiaoXiao implements  DaDa ,LaLa{
}

說明:這里不能通過 javac XiaoXiao.java生成XiaoXiao.class文件了,因為會報錯。我分析原因是因為你手動編譯是無法找到DaDa ,LaLa編譯信息。

所以我們可以把整個項目啟動后,到target目錄下去找該class文件就可以。

在打開16進制文件。

我們看到該類的類索引在常量池0002位置 ,父類索引在常量池0003位。接口為0002代表該類實現了兩個接口,一個接口在常量池位置004,一個在常量池位置0005。

在看反編譯后的class文件。

驗證成功!

參考

1、深入了解java虛擬機第2版第六章

2、深入理解JVM-Class文件結構和類加載



只要自己變優秀了,其他的事情才會跟着好起來(少將4)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM