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); } }
- 第一個執行邏輯:Animal animal = new Animal("didid");就是讓JVM建立一個Animal物件,但是這時候方法區中沒有Animal類的資訊,所以JVM馬上載入Animal類,把Animal類的型別資訊放到方法區中。
- 載入完Animal類之後,Java虛擬機器做的第一件事情就是在堆區中為一個新的Animal例項分配記憶體, 然後呼叫建構函式初始化Animal例項,這個Animal例項持有著指向方法區的Animal類的型別資訊(其中包含有方法表,java動態繫結的底層實現)的引用。
- 當使用animal.printName()的時候,JVM根據animal引用找到Animal物件,然後根據Animal物件持有的引用定位到方法區中Animal類的型別資訊的方法表,獲得printName()函式的位元組碼的地址。
- 開始執行printName()函式。
三 總結
算是個人的一個總結,集大家所長,供大家參考,有不對的地方請指教!
參考:https://www.cnblogs.com/qiumingcheng/p/5398610.html