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版第六章
只要自己變優秀了,其他的事情才會跟着好起來(少將4)