(轉)《Java虛擬機原理圖解》1.4 class文件中的字段表集合--field字段在class文件中是怎樣組織的

原文地址:http://blog.csdn.net/luanlouis/article/details/41046443


0.前言

         瞭解JVM虛擬機原理是每一個Java程序員修煉的必經之路。但是由於JVM虛擬機中有很多的東西講述的比較寬泛,在當前接觸到的關於JVM虛擬機原理的教程或者博客中,絕大部分都是充斥的文字性的描述,很難給人以形象化的認知,看完之後感覺還是稀裏糊塗的。

         感於以上的種種,我打算把我在學習JVM虛擬機的過程中學到的東西,結合自己的理解,總結成《Java虛擬機原理圖解》 這個系列,以圖解的形式,將抽象的JVM虛擬機的知識具體化,希望能夠對想了解Java虛擬機原理的的Java程序員 提供點幫助。


讀完本文,你將會學到:

1、類中定義的field字段是如何在class文件中組織的

2、不同的數據類型在class文件中是如何表示的

3、static final類型的field字段的初始化賦值問題

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;,那麼在訪問標誌上,第15ACC_PRIVATE和第13ACC_STATIC標誌位都應該爲1。fieldstr的訪問標誌信息應該是如下所示:


如上圖所示,str字段的訪問標誌的值爲0x000A,它由兩個修飾符ACC_PRIVATEACC_STATIC組成。

根據給定的訪問標誌(access_flags),我們可以通過以下運算來得到這個域有哪些修飾符:

上面列舉的str字段的訪問標誌的值爲000A,那麼分別域上述的標誌符的特徵值取&,結果爲1的只有ACC_PRIVATEACC_STATIC,所以該字段的標誌符只有有ACC_PRIVATEACC_STATIC



5. 字段的數據類型表示和字段名稱表示

class文件對數據類型的表示如下圖所示:



field字段名稱,我們定義了一個形如private static String strfield字段,其中"str"就是這個字段的名稱。

class文件將字段名稱和field字段的數據類型表示作爲字符串存儲在常量池中。在field_info結構體中,緊接着訪問標誌的,就是字段名稱索引和字段描述符索引,它們分別佔有兩個字節,其內部存儲的是指向了常量池中的某個常量池項的索引,對應的常量池項中存儲的字符串,分別表示該字段的名稱和字段描述符。


6.屬性表集合-----靜態field字段的初始化

在定義field字段的過程中,我們有時候會很自然地對field字段直接賦值,如下所示:

  1. public static final int MAX=100;  
  2. public  int count=0;  
對於虛擬機而言,上述的兩個field字段賦值的時機是不同的:
  •        對於非靜態(即無static修飾)的field字段的賦值將會出現在實例構造方法<init>()
  •        對於靜態的field字段,有兩個選擇:1、在靜態構造方法<cinit>()中進行;2 、使用ConstantValue屬性進行賦值
Sun javac編譯器對於靜態field字段的初始化賦值策略

目前的Sun javac編譯器的選擇是:如果使用finalstatic同時修飾一個field字段,並且這個字段是基本類型或者String類型的,那麼編譯器在編譯這個字段的時候,會在對應的field_info結構體中增加一個ConstantValue類型的結構體,在賦值的時候使用這個ConstantValue進行賦值;如果該field字段並沒有被final修飾,或者不是基本類型或者String類型,那麼將在類構造方法<cinit>()中賦值。

對於上述的public static final init MAX=100;   javac編譯器在編譯此field字段構建field_info結構體時,除了訪問標誌、名稱索引、描述符索引外,會增加一個ConstantValue類型的屬性表。


7.實例解析:

定義如下一個簡單的Simple類,然後通過查看Simple.class文件內容並結合javap -v Simple 生成的常量池內容,分析str field字段的結構:

  1. package com.louis.jvm;  
  2.   
  3. public class Simple {  
  4.   
  5.     private  transient static final String str ="This is a test";  
  6. }  


注:

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賦值。







作者的話

    本文是《Java虛擬機原理圖解》系列的其中一篇,如果您有興趣,請關注該系列的其他文章~

   覺得本文不錯,順手點個贊哦~~您的鼓勵,是我繼續分享知識的強大動力!

    

 

-----------------------------------------------------------------------------------------------------------------------------------------

                                                                              本文源自  http://blog.csdn.net/luanlouis/,如需轉載,請註明出處,謝謝!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章