java字節碼《java虛擬機》要點精煉


本文圖片以及部分內容來自Java字節碼增強探祕
Java字節碼的介紹

字節碼基礎

.java文件通過javac編譯後將得到一個.class文件,如下圖所示,class文件中都是16進制數。
在這裏插入圖片描述
java字節碼主要包括以下幾部分。
在這裏插入圖片描述
(1)魔數,魔數固定的值是CAFEBABY,佔用四個字節,用此來判斷該文件是否可以被虛擬機所接收。我理解在類加載過程中,校驗的第一步格式校驗就是去校驗魔數。

補充:爲什麼CA佔一個字節呢,因爲一個字節是8位01,而這個是16進制的,最大可以到15,15就是F,也就是1111,所以一個16進制數需要4位01來存儲,因此兩個16進制數就是一字節。

(2)版本數:緊接着魔數的後4位數就是版本數,虛擬機要求不能執行超過其版本號的class文件。

(3)常量池:常量池中存儲的是字面量與符號引用。由於存儲的數量不定,因此需要兩字節來存儲數量。常量池中存儲與常規不同,它的存儲是以1開始的,因此比如值爲0x0016,對應22。常量池中有21個常量,其下標爲1-21。
在這裏插入圖片描述
(4)訪問標誌:之後的兩個字節表示訪問標誌,包括: 這個Class是類還是接口; 是否定義爲public類型; 是否定義爲abstract類型; 如果是類的話, 是否被聲明爲final等。
(5) 當前類名:訪問標誌後的兩個字節,描述的是當前類的全限定名。這兩個字節保存的值爲常量池中的索引值,根據索引值就能在常量池中找到這個類的全限定名。
(6) 父類名稱:當前類名後的兩個字節,描述父類的全限定名,同上,保存的也是常量池中的索引值。
(7) 接口信息:父類名稱後爲兩字節的接口計數器,描述了該類或父類實現的接口數量。緊接着的n個字節是所有接口名稱的字符串常量的索引值。
(8) 字段表:字段表( field_info) 用於描述接口或者類中聲明的變量

字段可以包含字段的作用域(public、private、protected修飾符)、是實例變量還是類變量(static修飾符)、可變性(final)、併發可見性(volatile修飾符,是否強制從主內存讀寫)、可否被序列化(transient修飾符)、字段數據類型(基本類型、對象、數組)、字段名稱
在這裏插入圖片描述
描述符的作用是用來描述字段的數據類型、 方法的參數列表( 包括數量、 類型以及順序) 和返回值。
在這裏插入圖片描述
對應數組的話,int[] 會被描述爲[I,而java.lang.String[][]被描述爲[[java.lang.String
(9)方法表集合:方法表的結構如同字段表一樣, 依次包括了訪問標誌( access_flags) 、 名稱索引( name_index) 、 描述符索引( descriptor_index) 、 屬性表集合( attributes) 幾項。

字節碼指令

我們以這個例子爲例。

1 package com.company.niuke;
2
3 public class jvmtest {
4    public static void main(String[]args){
5        int  a  =  1 ;
6        int  b  =  2 ;
7        int  c  =  a  +  b ;
8    }
9}
10

對應的class文件如下,

  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 5 L0
    ICONST_1
    ISTORE 1
   L1
    LINENUMBER 6 L1
    ICONST_2
    ISTORE 2
   L2
    LINENUMBER 7 L2
    ILOAD 1
    ILOAD 2
    IADD
    ISTORE 3
   L3
    LINENUMBER 8 L3
    RETURN
   L4
    LOCALVARIABLE args [Ljava/lang/String; L0 L4 0
    LOCALVARIABLE a I L1 L4 1
    LOCALVARIABLE b I L2 L4 2
    LOCALVARIABLE c I L3 L4 3
    MAXSTACK = 2
    MAXLOCALS = 4

可以看到LINENUMBER代表當前對應的行。

第五行的int a = 1其實對應兩個字節碼:(1)iconst 1:將整形常量1放入操作數棧。(2)istore 1:在索引爲1的位置將第一個操作數出棧(一個int值)並且將其存進本地變量,相當於變量a。

第六行與第五行相似。

而第七行則涉及把a和b從本地變量中取出,放入操作數棧中ILOAD 1

iadd:把操作數棧中的前兩個int值出棧並相加,將相加的結果放入操作數棧。

ISTORE 3:將操作數棧中的3從棧中取出並存入本地變量。

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