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

0.前言

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

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


讀完本文,你將會學到:

一、類中定義的field字段是如何在class文件中組織的程序員

二、不一樣的數據類型在class文件中是如何表示的數組

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

1.概述

     字段表集合是指由若干個字段表(field_info)組成的集合。對於在類中定義的若干個字段,通過JVM編譯成class文件後,會將相應的字段信息組織到一個叫作字段表集合的結構中,字段表集合是一個類數組結構,以下圖所示:學習

注意:這裏所講的字段是指在類中定義的靜態或者非靜態的變量,而不是在類中的方法內定義的變量。請注意區別。
ui

好比,若是某個類中定義了5個字段,那麼,JVM在編譯此類的時候,會生成5個字段表(field_info)信息,而後將字段表集合中的字段計數器的值設置成5,將5個字段表信息依次放置到字段計數器的後面。lua

2. 字段表集合在class文件中的位置

字段表集合緊跟在class文件的接口索引集合結構的後面,以下圖所示:spa


3. Java中的一個Field字段應該包含那些信息?------字段表field_info結構體的定義    

  

    針對上述的字段表示,JVM虛擬機規範規定了field_info結構體來描述字段,其表示信息以下:
.net

下面我將一一講解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字段,有兩個選擇:一、在靜態構造方法<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. public class Simple {
  3. private transient static final String str = "This is a test";
  4. }


注:

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文件的核心,

本文源自  http://blog.csdn.net/luanlouis/

相關文章
相關標籤/搜索