一、類加載概述
在JVM執行我們寫好的代碼的過程中,具體是在代碼中用到這個類的時候將“.class”文件加載進JVM內存里,類的加載到使用具體經過下面這幾個過程:
加載 -> 驗證 -> 准備 -> 解析 -> 初始化 -> 使用 -> 卸載
各階段具體工作如下圖(圖片參考一):
二、各階段工作詳細描述(圖片參考一)
三、實戰代碼理解
在含有幾個“.class”文件的字節碼文件中,JVM首先會載入含有main方法的字節碼文件。代碼執行時,首先將class文件加載進內存,
在完成驗證、准備、解析、初始化等操作后,開始執行main函數方法。其中
初始化步驟完成靜態代碼塊的執行以及類靜態成員變量等的初始化,Java 虛擬機會通過加鎖的方式來確保類的初始化方法僅被執行一次,這里的初始化步驟是線程安全的。
具體代碼執行情況如下圖:
Main.java文件:
1 public class Main{ 2 /* 3 代碼執行時,首先將class文件加載進內存,在完成驗證、准備、解析、初始化等操作后,開始執行 4 main函數方法。其中初始化步驟完成靜態代碼塊的執行以及類靜態成員變量等的初始化 5 */ 6 public static Static sta = new Static(); 7 public int a = 0; 8 public static void main(String[] args){ 9 System.out.println("A"); 10 new Main(); //這里加載過程只執行一次 11 new Main(); 12 new Static(); //也只執行一次加載過程 13 } 14 public Main(){ 15 System.out.println("B"); 16 } 17 //代碼塊是在實例化的時候運行的,實例化時代碼塊運行完才運行構造器 18 { 19 System.out.println("C"); 20 } 21 static{ 22 System.out.println("D"); 23 } 24 }
Static.java文件:
1 public class Static{ 2 static{ 3 System.out.println("E"); 4 } 5 public Static(){ 6 System.out.println("F"); 7 } 8 { 9 System.out.println("G"); 10 } 11 }
上述代碼執行結果:
1 E 2 G 3 F 4 D 5 A 6 C 7 B 8 C 9 B 10 G 11 F
具體執行過程如下:
1.JVM載入Main.class文件,在類加載的初始化階段,完成了類中的靜態成員變量初始化以及靜態代碼塊的執行,在此代碼的靜態成員變量初始化過程中,由於需要Static類的實例化,所以JVM將Static.class文件載入內存,完成Static的類加載過程,所以此時代碼執行結果為上述的1、2、3、4(其中1、2、3執行順序看下面解釋)
2.完成Main的類加載階段后,開始按順序執行main方法,其中連續進行幾次實例化。在實例化階段,先進行代碼塊的執行,然后進行相應構造方法的執行。注意,在后續的類實例化階段,由於前面已經進行過相應類的加載過程,所以后續不再進行對應的類初始化過程,僅僅進行實例化階段。具體執行結果如5、6、7、8、9、10、11
參考:1.java團長公眾號https://mp.weixin.qq.com/s/Xri-gc5B_cxpgWluLFgJRQ
2.狸貓技術窩《從0開始帶你成為JVM實戰高手》