瞭解JVM虛擬機原理是每個Java程序員修煉的必經之路。可是因爲JVM虛擬機中有不少的東西講述的比較寬泛,在當前接觸到的關於JVM虛擬機原理的教程或者博客中,絕大部分都是充斥的文字性的描述,很難給人以形象化的認知,看完以後感受仍是稀裏糊塗的。
html
感於以上的種種,我打算把我在學習JVM虛擬機的過程當中學到的東西,結合本身的理解,總結成《Java虛擬機原理圖解》 這個系列,以圖解的形式,將抽象的JVM虛擬機的知識具體化,但願可以對想了解Java虛擬機原理的的Java程序員 提供點幫助。
java
字段表集合是指由若干個字段表(field_info)組成的集合。對於在類中定義的若干個字段,通過JVM編譯成class文件後,會將相應的字段信息組織到一個叫作字段表集合的結構中,字段表集合是一個類數組結構,以下圖所示:學習
注意:這裏所講的字段是指在類中定義的靜態或者非靜態的變量,而不是在類中的方法內定義的變量。請注意區別。
ui
好比,若是某個類中定義了5個字段,那麼,JVM在編譯此類的時候,會生成5個字段表(field_info)信息,而後將字段表集合中的字段計數器的值設置成5,將5個字段表信息依次放置到字段計數器的後面。lua
字段表集合緊跟在class文件的接口索引集合結構的後面,以下圖所示:spa
針對上述的字段表示,JVM虛擬機規範規定了field_info結構體來描述字段,其表示信息以下:
.net
下面我將一一講解FIeld_info的組成元素:訪問標誌(access_flags)、名稱索引(name_index)、描述索引(descriptor_index)、屬性表集合
如上圖所示定義的field_info結構體,field字段的訪問標誌(access_flags)佔有兩個字節,它可以表述的信息以下所示:
舉例:若是咱們在某個類中有定義field域:private static String str;,那麼在訪問標誌上,第15位ACC_PRIVATE和第13位ACC_STATIC標誌位都應該爲1。field域str的訪問標誌信息應該是以下所示:
如上圖所示,str字段的訪問標誌的值爲0x000A,它由兩個修飾符ACC_PRIVATE和ACC_STATIC組成。
根據給定的訪問標誌(access_flags),咱們能夠經過如下運算來獲得這個域有哪些修飾符:
上面列舉的str字段的訪問標誌的值爲000A,那麼分別域上述的標誌符的特徵值取&,結果爲1的只有ACC_PRIVATE和ACC_STATIC,因此該字段的標誌符只有有ACC_PRIVATE和ACC_STATIC。
class文件對數據類型的表示以下圖所示:
field字段名稱,咱們定義了一個形如private static String str的field字段,其中"str"就是這個字段的名稱。
class文件將字段名稱和field字段的數據類型表示做爲字符串存儲在常量池中。在field_info結構體中,緊接着訪問標誌的,就是字段名稱索引和字段描述符索引,它們分別佔有兩個字節,其內部存儲的是指向了常量池中的某個常量池項的索引,對應的常量池項中存儲的字符串,分別表示該字段的名稱和字段描述符。
在定義field字段的過程當中,咱們有時候會很天然地對field字段直接賦值,以下所示:
-
public
static
final
int MAX=
100;
-
public
int count=
0;
對於虛擬機而言,上述的兩個field字段賦值的時機是不一樣的:
對於上述的public static final init MAX=100; javac編譯器在編譯此field字段構建field_info結構體時,除了訪問標誌、名稱索引、描述符索引外,會增長一個ConstantValue類型的屬性表。
定義以下一個簡單的Simple類,而後經過查看Simple.class文件內容並結合javap -v Simple 生成的常量池內容,分析str field字段的結構:
-
package com.louis.jvm;
-
-
public
class Simple {
-
-
private
transient
static
final String str =
"This is a test";
-
}
注:
1. 字段計數器中的值爲0x0001,表示這個類就定義了一個field字段
2. 字段的訪問標誌是0x009A,二進制是00000000 10011010,即第九、十二、1三、15位標誌位爲1,這個字段的標誌符有:ACC_TRANSIENT、ACC_FINAL、ACC_STATIC、ACC_PRIVATE;3. 名稱索引中的值爲0x0005,指向了常量池中的第5項,爲「str」,代表這個field字段的名稱是str;
4. 描述索引中的值爲0x0006,指向了常量池中的第6項,爲"Ljava/lang/String;",代表這個field字段的數據類型是java.lang.String類型;
5.屬性表計數器中的值爲0x0001,代表field_info還有一個屬性表;
6.屬性表名稱索引中的值爲0x0007,指向常量池中的第7項,爲「ConstantValue」,代表這個屬性表的名稱是ConstantValue,即屬性表的類型是ConstantValue類型的;
7.屬性長度中的值爲0x0002,由於此屬性表是ConstantValue類型,它的值固定爲2;
8.常量值索引 中的值爲0x0008,指向了常量池中的第8項,爲CONSTANT_String_info類型的項,表示「This is a test」 的常量。在對此field賦值時,會使用此常量對field賦值。
8.您還須要瞭解什麼
簡單地說,對於一個類而言,它有兩部分組成:field字段和 method方法。本文主要介紹了field字段,那還剩些一個method方法method方法啦。method方法但是說是class文件中最爲重要的一部分了,它包含了方法的實現代碼,即機器指令,機器指令是整個class文件的核心,