要知道static靜態塊什么時候執行,我們需要先搞清楚運行一個類,jvm會做什么事情。
1、類加載。
采用雙親委派模式加載類,子類會交給父類的classloader去加載,如果父類加載不到自己才會嘗試加載。最終功能是將java字節碼轉換為JVM的class對象。
2、鏈接。
將Java二進制代碼合並到JVM的運行時狀態中。在鏈接之前必須保證類已經被加載。期間會經過驗證、准備和解析等幾個步驟。驗證確保java類的二進制表示在結構上是完全正確的,如果不正確拋出java.lang.VerifyError。准備過程則是創建類中的靜態域並默認賦初值。解析的過程確保類引用的類能被找到。
3、初始化。
當一個類真正被使用的時候,JVM會初始化該類。主要操作就是執行靜態代碼塊和初始化靜態域。
4、實例化。
在內存中開辟堆空間。
從上我們可以看出,靜態代碼塊在類初始化的時候執行。反應到代碼上也就是在class.forName時執行。
public class Word{ static{ System.out.println("Word static initialization!"); } public void start(){ System.out.println("Word starts"); } }
public class Office{ public static void main(String args[])throws Exception{ args[0]="com.bjtest.belen.Word"; Office off = new Office(); System.out.println("類別准備載入"); Class c = Class.forName(args[0],true,off.getClass().getClassLoader()); System.out.println("類別准備實例化"); Class c1 = Class.forName(args[0],true,off.getClass().getClassLoader()); Object o = c.newInstance(); Object o2= c.newInstance(); } }
執行代碼結果如下:
類別准備載入
Word static initialization!
類別准備實例化
從上分析得出如下結論,類只被加載一次。並且靜態代碼塊只在類初始化的時候被執行一次,第二次不會執行。
但是如果將上述代碼改為:
public class Office{ public static void main(String args[])throws Exception{ args[0]="com.bjtest.belen.Word"; Office off = new Office(); System.out.println("類別准備載入"); Class c = Class.forName(args[0],false,off.getClass().getClassLoader()); System.out.println("類別准備實例化"); Class c1 = Class.forName(args[0],true,off.getClass().getClassLoader()); Object o = c.newInstance(); Object o2= c.newInstance(); } }
執行結果如下:
類別准備載入
類別准備實例化
Word static initialization!
從上分析我們可以得出如下結論:
1、我們可以控制靜態代碼塊不在初始化時執行
2、如果不在初始化時執行,那么一定在實例化時執行
3、靜態代碼塊只執行一次