上一篇博客講【JVM虛擬機】(5)---深刻理解JVM-Class中常量池javascript
咱們知道一個class文件正常能夠分爲7個部分:html
訪問標誌
類索引、父類索引、接口索引
那麼這篇博客主要講有關 訪問標誌 和 類索引、父類索引、接口索引 相關的理解和代碼示例。java
先通俗的說下這兩個的做用:測試
訪問標誌
: 告知該類是一個什麼類型的類,是普通類?仍是接口?仍是枚舉?或者其它類,是用什麼修飾符修飾該類的。spa
類索引、父類索引、接口索引
: 告知該類全限名的常量池地址,有繼承的話父類全限名的常量池地址,實現接口的話接口全限名的常量池地址(接口能夠多個)。code
先對上篇博客作個補充:上篇博客雖說了常量池但對class總體文件結構並無說清楚,其實一個class文件即htm
.class
文件本質上就是一張表
,由下表所示的數據項構成。blog
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135031721-1835822396.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="612">繼承
上圖也就是一開始所講的7個部分組成。索引
<br>
有關訪問標誌
找了不少資料,也看了《深刻了解java虛擬機》書中第六章給的有關訪問標誌的信息,網上幾乎講訪問標誌都是下面這張圖,而後寫個pulic class 類 一測試,果真是0021 表明 ACC_PUBLIC+ACC_SUPER
這樣一看是沒毛病。可是都沒有再寫一個接口來驗證的,若是本身寫個接口就會發現下面我圈紅的地方說,JDK1.2後該處必須爲真 是不對的
。先看圖。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135129522-1831389208.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="700" height="412">
思考
:就比如爲何ACC_PUBLIC是00 01?如何產生的呢。
訪問標誌
實際上就是一系列組合,由於有16位因此共有16個標誌可使用,可是目前就定義了8個,剩下的估計是給jdk9和10......預留的吧。這8個如圖所示。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135139548-792467058.png" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="426">
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135148442-1272202826.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="420">
講完理論,接下來咱們進行代碼測試,爲了校驗更佳準確我寫個普通類和接口分別測試:
public class XiaoXiao { }
在同一目錄生成成class文件
javac XiaoXiao.java
在看反編譯class文件
javap -v XiaoXiao.class
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135200951-1944917775.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="274">
咱們發現這裏flags爲: ACC_PUBLIC, ACC_SUPER
,那這麼推算那麼十六進制應該是0021。
那咱們再來查看XiaoXiao.class的十六進制數據
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135210605-118543476.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="370">
完美吻合。
public interface DaDa { }
一樣先生成class文件在反編譯class文件
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135219909-386750991.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="247">
看圖咱們能夠發現flags值爲:ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
,這個也很好理解接口自己就是抽象類。那麼加起來就是0601
。但這裏和上圖有點不符的地方就是圖中說ACC_SUPER只要是JDK1.2必須爲真,而這裏明顯不爲真,因此有關這點並不許確。
那咱們再將class文件轉位16進制驗證。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135232383-1170041644.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="218">
這麼一來驗證也是經過的。
有關ACC_SUPER不許確的問題,應該是ACC_SUPER不會
是在JDK1.2之後必須爲真,應該以下描述:
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135241834-913919387.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="410">
<br>
在 .class 文件中由這三項數據來肯定這個類
的繼承關係。
一、類索引
:u2 數據類型,用於肯定這個類
的全限定名。
二、父類索引
:u2 數據類型,用於肯定這個類的父類
的全限定名。
三、接口索引
:u2 數據類型的集合,用於描述類實現了哪些接口
,這些被實現的接口將按照 implements 語句後的順序從左至右排列在接口索引集合中。
接口索引集合分爲兩部分,第一部分表示接口計數器
(interfaces_count),是一個 u2 類型的數據,第二部分是接口索引表
表示接口信息,緊跟在接口計數器以後。
若一個類實現的接口爲 0,則接口計數器的值爲 0,接口索引表不佔用任何字節。
一樣這裏測試寫兩個測試類來測試。
public class XiaoXiao { }
一樣生成class文件,而後查看16進制數據
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135252392-556980563.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="425">
咱們看到該類的類索引在常量池0002位置 ,父類索引在常量池0003位置,接口爲0000表明該類沒有實現任何接口。
而後咱們在反編譯XiaoXiao.class文件,方便咱們查找常量池。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135305029-1927119339.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="273">
真的是一目瞭然,常量池0002就是當前類,0003父類爲默認繼承了老祖宗Object。
完美!
爲了更加深入理解,這裏再寫一個類實現兩個接口的類,在來查看。
//接口 public interface DaDa { } //接口 public interface LaLa { } //類實現上面兩個接口 public class XiaoXiao implements DaDa ,LaLa{ }
說明
:這裏不能經過 javac XiaoXiao.java
生成XiaoXiao.class文件了,由於會報錯。我分析緣由是由於你手動編譯是沒法找到DaDa ,LaLa編譯信息。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135321017-796665369.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="385">
因此咱們能夠把整個項目啓動後,到target目錄下去找該class文件就能夠。
在打開16進制文件。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135331220-1772694961.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="260">
咱們看到該類的類索引在常量池0002位置 ,父類索引在常量池0003位。接口爲0002表明該類實現了兩個接口,一個接口在常量池位置004,一個在常量池位置0005。
在看反編譯後的class文件。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135343028-161944163.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="286">
驗證成功!
##<font color=#FFD700>參考 </font>
一、深刻了解java虛擬機第2版第六章
<br> <br> ``` 只要本身變優秀了,其餘的事情纔會跟着好起來(少將4) ```