標籤:oid 分配 部分 jvm 14. vat 不用 系統 tag
title: java類載入系列之---類編譯揭秘
date: 2018-07-17 11:48:02
category: 原創
tags: [Java,Java類編譯載入執行專題]
---
本文為java類編譯載入執行系列文章第一篇:類編譯揭秘
第一步:我們寫一個java源檔案,如下:
public class CompileTest { public static void main(String[] args) { User user = new User(1, "Vale"); System.out.println(user.getUserName()); }}
public class User { private int userId; private String userName; public User(int userId, String userName) { super(); this.userId = userId; this.userName = userName; }}//省略getter setter
第二步(編譯): 建立完源檔案之後,程式會先被編譯為.class檔案。Java編譯一個類時,如果這個類所依賴的類還沒有被編譯,編譯器就會先編譯這個被依賴的類,然後引用,否則直接引用,這個有點象make。如果java編譯器在指定目錄下找不到該類所其依賴的類的.class檔案或者.java源檔案的話,編譯器話報“cant find symbol”的錯誤。class檔案包括以下幾個部分:魔數、副版本號碼、主要版本,常量池,方法位元組碼。
編譯後的位元組碼檔案格式主要分為兩部分:常量池和方法位元組碼。常量池記錄的是代碼出現過的所有token(類名,成員變數名等等)以及符號引用(方法引用,成員變數引用等等);方法位元組碼放的是類中各個方法的位元組碼。下面是CompileTest .class通過反組譯碼的結果,我們可以清楚看到.class檔案的結構:
第三步(運行):java類啟動並執行過程大概可分為兩個過程:1、類的載入 2、類的執行。需要說明的是:JVM主要在程式第一次主動使用類的時候,才會去載入該類。也就是說,JVM並不是在一開始就把一個程式就所有的類都載入到記憶體中,而是到不得不用的時候才把它載入進來,而且只載入一次。
下面是程式啟動並執行詳細步驟:
在編譯好java程式得到CompileTest .class檔案後,在命令列上敲java CompileTest 。系統就會啟動一個jvm進程,jvm進程從classpath路徑中找到一個名為CompileTest .class的二進位檔案,將CompileTest 的類資訊載入到運行時資料區的方法區內,這個過程叫做CompileTest 類的載入。
然後JVM找到CompileTest 的主函數入口,開始執行main函數。
main函數的第一條命令是User user = new User(1, "Vale");;就是讓JVM建立一個User對象,但是這時候方法區中沒有User類的資訊,所以JVM馬上載入User類,把User類的類型資訊放到方法區中。
載入完User類之後,Java虛擬機器做的第一件事情就是在堆區中為一個新的User執行個體分配記憶體, 然後調用建構函式初始化User執行個體,這個User執行個體持有著指向方法區的User類的類型資訊(其中包含有方法表,java動態綁定的底層實現)的引用。
當使用user.getUserName()的時候,JVM根據user引用找到User對象,然後根據User對象持有的引用定位到方法區中User類的類型資訊的方法表,獲得getUserName()函數的位元組碼的地址。
開始運行getUserName()函數。
java類編譯過程