java整個編譯以及運行的過程至關繁瑣,我就舉一個簡單的例子說明:html
Java程序從源文件建立到程序運行要通過兩大步驟:java
一、源文件由編譯器編譯成字節碼(ByteCode); 函數
二、字節碼由java虛擬機解釋運行。由於java程序既要編譯同時也要通過JVM的解釋運行,因此說Java被稱爲半解釋語言this
( "semi-interpreted" language)spa
第一步(編譯):建立完源文件以後,程序先要被JVM中的java編譯器進行編譯爲.class文件。java編譯一個類時,若是這個類所依賴的類尚未被編譯,命令行
編譯器會自動的先編譯這個所依賴的類,而後引用。若是java編譯器在指定的目錄下找不到該類所依賴的類的 .class字節碼(bytecode)文件或者 .java源文件,就會報"Cant found sysbol"的異常錯誤。指針
編譯後的字節碼文件格式主要分爲兩部分:常量池和方法字節碼。常量池記錄的是代碼出現過的(常量、類名、成員變量等)以及符號引用(類引用、方法引用,成員變量引用等);方法字節碼中放的是各個方法的字節碼。code
第二步(運行):java類運行的過程大概分爲兩個步驟:(1)類的加載 (2)類的執行。須要說明的一點的是:JVM主要在程序第一次運行時主動使用類的時候,纔會當即去加載。換言之,JVM並非在運行時就會把全部使用到的類都加載到內存中,而是用到,不得不加載的時候,才加載進來,並且只加載一次!htm
根據上面的程序,詳解該程序運行的詳細步驟:對象
(1)在類路徑下找到編譯好的 java 程序中獲得 Test.class 字節碼文件後,在命令行上敲 java Test,系統就會啓動一個 JVM 進程,JVM進程從classpath路徑下找到一個名爲Test.class的二進制文件,將Test.class文件中的類信息加載到運行時數據區的方法區中,這一過程叫作類的加載。(只有類信息在方法區中,才能建立對象,使用類中的成員變量)
(2)JVM 找到main方法的主函數入口, 持有一個指向當前類(Test)常量池的指針,而常量池中的第一項是發現是一個對Animal對象的符號引用,而且main方法中第一條指令是Animal animal = new Animal("super_yc"),就是讓JVM建立一個Animal對象,可是方法區中尚未Animal類的類信息,因而JVM就要立刻的加載Animal類,將Animal類信息放入到方法區中,因而JVM 以一個直接指向方法區 Animal類的指針替換了常量池中第一項的符號引用。
(3)加載完Animal類的信息之後,JVM虛擬機就會在堆內存中爲一個Animal類實例分配內存,而後調用其構造函數初始化Animal實例,這個實例持有指向方法區的Animal類的類型信息(其中包含有方法表,java動態綁定的底層實現)的引用。(animal指向了Animal對象的引用會自動的放在棧中,字符串常量"super_yc"會自動的放在方法區的常量池中,對象會自動的放入堆區)
(4)當使用 animal.printName()的時候,JVM根據棧中animal引用找到Animal對象,而後根據Animal對象持有的引用定位到方法區中Animal類的類型信息方法表,得到printName()函數的字節碼地址,而後開始運行函數。
參考資料:
https://wenku.baidu.com/view/32208418650e52ea55189863.html
http://hxraid.iteye.com/blog/676235
http://hxraid.iteye.com/blog/428891
https://wenku.baidu.com/view/32208418650e52ea55189863.html