1. 程式人生 > >Java類編譯 執行

Java類編譯 執行

本人最近學習一些有關jvm東西,談談對Java編譯 和 執行時的一點拙見

一 編譯

目的時生成位元組碼檔案,class檔案

生成方法

1 剛學java時,javac xx.java

2 編輯器自動幫我們編輯

 

 編譯後的位元組碼檔案格式主要分為兩部分:常量池方法位元組碼。常量池記錄的是程式碼出現過的所有token(類名,成員變數名等等)以及符號引用(方法引用,成員變數引用等等);方法位元組碼放的是類中各個方法的位元組碼。

 

二 執行

這一塊內容很多:大致有兩個過程:1、類的載入  2、類的執行。

1 講到類載入過程,比較經典的回答:

一般來說,我們把 Java 的類載入過程分為三個主要步驟:載入、連結、初始化,具體行為在

首先是載入階段(Loading),它是 Java 將位元組碼資料從不同的資料來源讀取到 JVM 中,並對映為 JVM 認可的資料結構(Class 物件),這裡的資料來源可能是各種各樣的形態,
如 jar 檔案、class 檔案,甚至是網路資料來源等;如果輸入資料不是 ClassFile 的結構,則會丟擲 ClassFormatError。

第二階段是連結(Linking),這是核心的步驟,簡單說是把原始的類定義資訊平滑地轉化入 JVM 執行的過程中。這裡可進一步細分為三個步驟:
驗證(Verification),這是虛擬機器安全的重要保障,JVM 需要核驗位元組資訊是符合 Java 虛擬機器規範的,否則就被認為是 VerifyError,這樣就防止了惡意資訊或者不合規的資訊危害 JVM 的執行,驗證階段有可能觸發更多 class 的載入。
準備(Preparation),建立類或介面中的靜態變數,並初始化靜態變數的初始值。但這裡的“初始化”和下面的顯式初始化階段是有區別的,側重點在於分配所需要的記憶體空間,不會去執行更進一步的 JVM 指令。


解析(Resolution),在這一步會將常量池中的符號引用(symbolic reference)替換為直接引用。

最後是初始化階段(initialization),這一步真正去執行類初始化的程式碼邏輯,包括靜態欄位賦值的動作,以及執行類定義中的靜態初始化塊內的邏輯,
編譯器在編譯階段就會把這部分邏輯整理好,父型別的初始化邏輯優先於當前型別的邏輯。

 

2 類的執行


public class MainApp {  
    public static void main(String[] args) {  
        Animal animal = new Animal("didid");  
        animal.printName();  
    }  
}  

public class Animal {  
    public String name;  
    public Animal(String name) {  
        this.name = name;  
    }  
    public void printName() {  
        System.out.println("Animal:"+name);  
    }  
}  

 

  1. 第一個執行邏輯:Animal  animal = new Animal("didid");就是讓JVM建立一個Animal物件,但是這時候方法區中沒有Animal類的資訊,所以JVM馬上載入Animal類,把Animal類的型別資訊放到方法區中。
  2. 載入完Animal類之後,Java虛擬機器做的第一件事情就是在堆區中為一個新的Animal例項分配記憶體, 然後呼叫建構函式初始化Animal例項,這個Animal例項持有著指向方法區的Animal類的型別資訊(其中包含有方法表,java動態繫結的底層實現)的引用。
  3. 當使用animal.printName()的時候,JVM根據animal引用找到Animal物件,然後根據Animal物件持有的引用定位到方法區中Animal類的型別資訊的方法表,獲得printName()函式的位元組碼的地址。
  4. 開始執行printName()函式。

 

 

三 總結

算是個人的一個總結,集大家所長,供大家參考,有不對的地方請指教!

參考:https://www.cnblogs.com/qiumingcheng/p/5398610.html