JVM:四、類文件結構解析

虛擬機的語言無關性靠的是字節碼來實現的,虛擬機不和包括Java在內的任何語言綁定,只和“Class文件”綁定,Java,Jruby,Groovy程序經過各自的編譯器形成字節碼文件(.class)或叫做類文件。虛擬機處理類文件。類文件結構主要包括以下幾部分:Class文件版本 + 常量池 + 訪問標誌 + 類索引父類索引接口索引集合 + 字段表 + 方法表 + 屬性表

1. 類文件結構

常量池

可以理解爲Class的資源倉庫,佔用空間最大的數據項目之一,是一個表類型數據項目,一個常量就是一個表,一共有21個類型的表。

它與很多的結構都有關聯,例如字段表和方法表都會用到常量池,算是很複雜的一個部分。主要有字面量和符號引用組成。字面量就是文本字符串和final常量值,符號引用包含三類:類和接口的全限定名,字段的名稱和描述符,方法的名稱和描述符。

在這列出21個類型的表的幾種:整形字面量,字符串字面量,類和接口的符號引用,字段的符號引用,類中方法的符號引用,接口中方法的符號引用,表示方法類型,表示方法句柄。。。

訪問標誌

用於標識這個類或接口的訪問信息,例如這個Class是接口還是類,是否定義爲public類型,是否定義爲abstract類型,是否聲明爲final。

類索引,父類索引,接口索引集合

確定類的繼承關係。其中類索引用於確定這個類的全限定名。由於類只可以單繼承,接口可以多繼承,所以父類索引只有一個,接口索引是集合;由於所有的類都是繼承自Object,所以除了Object外父類索引不能爲0。(全限定名這些名稱都存在常量池裏,更具體一點是常量池裏的類和接口符號引用表)

字段表集合

接口或類中聲明的變量,可以是類級變量可以是實例變量,但不包括方法內的局部變量。

字段表一般有訪問標誌(access_logs),名稱索引(name_index),描述符索引(descriptor_index),屬性表集合(attributes)幾個項目,都是一個u2類型的數據,其中name_index表示字段的簡單名稱,descriptor_index表示描述符。

access_logs和類中的訪問標誌作用類似。可以設置的標誌位有:

字段的作用域(private,public,protected),實例變量還是類變量(有無static),可變性(final),併發可見性(volatile,是否強制從主內存讀寫),可否序列化(transient)。

以上各個修飾符都是布爾值,而字段叫什麼,是什麼類型是無法固定的,只可以通過name_index和descriptor_index兩個項目引用常量池中的常量來表述。

例如:private volatile Integer a = 23;那麼private,volatile這些屬性都會存在字段表裏,而 'a' 這個字段名需要地址從常量池裏取

方法表集合

方法表結構和字段表接口類似,依次包括訪問標誌(access_logs),名稱索引(name_index),描述符索引(descriptor_index),屬性表集合(attributes)。

因爲volatile和transient不可以用來修飾方法,所以方法表的訪問標誌中沒有了ACC_VOLATILE和ACC_TRANSIENT。

但是也會比字段表多一些訪問標誌位,例如ACC_ABSTRACT,ACC_SYNCHRONIZED。、

如果父類方法沒有被子類重寫,那麼子類中不會有父類的方法信息。

一般來說,編譯器也會自動添加一些方法,例如類初始化的類構造器<cliint>方法和實例構造器<init>方法

屬性表集合

會存一些方法內部的代碼(Code)供方法表調用,final關鍵字定義的常量(ConstantValue)字段表調用等等。

 

2. 字節碼指令

在此列出9種類型的字節碼指令

加載和存儲指令:iload,istore,bipush

運算指令:iadd,isub,imul

類型轉換指令

對象創建和訪問指令:

  • new,創建類的實例
  • newarray,創建數組
  • getfield,訪問實例字段
  • putfield,更改實例字段
  • getstatic,訪問static字段,或稱爲類變量
  • putstatic,更改類變量

擦作數棧指令:pop,dup

控制轉移指令:ifeq,iflt,goto

方法調用和返回指令:

  • invokevirtual,調用對象實例方法
  • invokeinterface,調用接口方法
  • invokespecial,調用特殊方法,例如實例初始化方法
  • invokestatic,調用類方法
  • invokedynamic,用於運行時動態解析出調用點限定符所引用的方法

異常處理指令:athrow

同步指令:不管是支持方法級的同步還是方法內部一段指令序列的同步,都是使用管程(Monitor)來實現的。

    方法的同步是隱式的,什麼意思呢?就是不需要字節碼指令來控制,虛擬機會從方法表的ACC_SYNCHRONIZED訪問標誌中獲取方法是否被設置了,如果設置了就要獲取管程纔可以執行方法。

    同步一段序列指令一般使用synchronized語句塊來實現。虛擬機通過monitorenter和monitorexit兩條指令來支持synchronized語義。

 

 

 

摘自《深入理解JVM虛擬機》

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章