原文地址:http://blog.csdn.net/luanlouis/article/details/41046443
0.前言
瞭解JVM虛擬機原理是每一個Java程序員修煉的必經之路。但是由於JVM虛擬機中有很多的東西講述的比較寬泛,在當前接觸到的關於JVM虛擬機原理的教程或者博客中,絕大部分都是充斥的文字性的描述,很難給人以形象化的認知,看完之後感覺還是稀裏糊塗的。
感於以上的種種,我打算把我在學習JVM虛擬機的過程中學到的東西,結合自己的理解,總結成《Java虛擬機原理圖解》 這個系列,以圖解的形式,將抽象的JVM虛擬機的知識具體化,希望能夠對想了解Java虛擬機原理的的Java程序員 提供點幫助。
1.概述
字段表集合是指由若干個字段表(field_info)組成的集合。對於在類中定義的若干個字段,經過JVM編譯成class文件後,會將相應的字段信息組織到一個叫做字段表集合的結構中,字段表集合是一個類數組結構,如下圖所示:
注意:這裏所講的字段是指在類中定義的靜態或者非靜態的變量,而不是在類中的方法內定義的變量。請注意區別。
比如,如果某個類中定義了5個字段,那麼,JVM在編譯此類的時候,會生成5個字段表(field_info)信息,然後將字段表集合中的字段計數器的值設置成5,將5個字段表信息依次放置到字段計數器的後面。
2. 字段表集合在class文件中的位置
字段表集合緊跟在class文件的接口索引集合結構的後面,如下圖所示:
3. Java中的一個Field字段應該包含那些信息?------字段表field_info結構體的定義
針對上述的字段表示,JVM虛擬機規範規定了field_info結構體來描述字段,其表示信息如下:
下面我將一一講解FIeld_info的組成元素:訪問標誌(access_flags)、名稱索引(name_index)、描述索引(descriptor_index)、屬性表集合
4. field字段的訪問標誌
如上圖所示定義的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。
5. 字段的數據類型表示和字段名稱表示
class文件對數據類型的表示如下圖所示:
field字段名稱,我們定義了一個形如private static String str的field字段,其中"str"就是這個字段的名稱。
class文件將字段名稱和field字段的數據類型表示作爲字符串存儲在常量池中。在field_info結構體中,緊接着訪問標誌的,就是字段名稱索引和字段描述符索引,它們分別佔有兩個字節,其內部存儲的是指向了常量池中的某個常量池項的索引,對應的常量池項中存儲的字符串,分別表示該字段的名稱和字段描述符。
6.屬性表集合-----靜態field字段的初始化
在定義field字段的過程中,我們有時候會很自然地對field字段直接賦值,如下所示:
- public static final int MAX=100;
- public int count=0;
- 對於非靜態(即無static修飾)的field字段的賦值將會出現在實例構造方法<init>()中
- 對於靜態的field字段,有兩個選擇:1、在靜態構造方法<cinit>()中進行;2 、使用ConstantValue屬性進行賦值
對於上述的public static final init MAX=100; javac編譯器在編譯此field字段構建field_info結構體時,除了訪問標誌、名稱索引、描述符索引外,會增加一個ConstantValue類型的屬性表。
7.實例解析:
定義如下一個簡單的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,即第9、12、13、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賦值。
-----------------------------------------------------------------------------------------------------------------------------------------