既然是雜談,那麼確定會比較雜亂,都是點到爲止,不回作過多的原理分析,若是對於原理,可能須要深刻了解JVM內部的東西了。<br/> 首先,我來展現一下幾個現象,而後對這幾個現象進行分析。<br/> 相關幾個類的定義java
<!-- lang:java--> package com.bieber.gc; public class Super { static{ System.out.println("super static block"); } public Super(){ System.out.println("super init"); } public void test(){ System.out.println("invoke test"); } } public class Main extends Super{ public Main() { System.out.println("main init"); } static{ System.out.println("sub static block"); } public void test(){ System.out.println("main test"); } }
這裏涉及到兩個類,下面針對這兩個類來寫幾個測試用例。<br/> ####用例一函數
<!-- lang:java--> public static void main(String[] args) throws Exception { try { System.out.println("#########start load class##########"); Thread.currentThread().getContextClassLoader().loadClass("com.bieber.gc.Main"); System.out.println(); System.out.println("#########start init class#########"); Main main = new Main(); System.out.println(); System.out.println("#########invoke#########"); main.test(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
#####輸出結果測試
<!-- lang:java --> #########start load class########## #########start init class######### super static block sub static block super init main init #########invoke######### main test
#####結果分析 能夠看到經過Classloader加載類的時候,並無執行static代碼塊,而static代碼塊卻放到了調用構造函數的時候執行了,而且static代碼塊是在構造函數以前執行的。同時在調用在子類重寫的方法時候,父類方法沒有執行(這點是毫無疑問的)。 ####用例二 #####用例代碼code
<!-- lang:java --> public static void main(String[] args) throws Exception { try { System.out.println("#########start load class##########"); Class.forName("com.bieber.gc.Main", true, Thread.currentThread().getContextClassLoader()); System.out.println(); System.out.println("#########start init class#########"); Main main = new Main(); System.out.println(); System.out.println("#########invoke#########"); main.test(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
#####執行結果內存
<!-- lang:java --> #########start load class########## super static block sub static block #########start init class######### super init main init #########invoke######### main test
#####結果分析 發現這個時候子類和父類的static代碼塊在調用構造函數以前執行的,這點說明此處的Class.forName
和ClassLoader
執行效果同樣。其餘部分和上面基本一致。 ####用例三 #####用例代碼ssl
<!-- lang:java --> public static void main(String[] args) throws Exception { try { System.out.println("#########start load class##########"); Class.forName("com.bieber.gc.Main", false, Thread.currentThread().getContextClassLoader()); System.out.println(); System.out.println("#########start init class#########"); Main main = new Main(); System.out.println(); System.out.println("#########invoke#########"); main.test(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
#####執行結果開發
<!-- lang:java --> #########start load class########## #########start init class######### super static block sub static block super init main init #########invoke######### main test
#####結果分析 這個執行結果和和用例一的結果同樣。get
####總結 上面列舉了三個測試用例,用例二和用例三的卻別就是 Class.forName("com.bieber.gc.Main", true, Thread.currentThread().getContextClassLoader());
和Class.forName("com.bieber.gc.Main", false, Thread.currentThread().getContextClassLoader());
的區別,這個很容易理解,其實第一個是在加載類的時候是初始化了類(Class)的其餘信息,而第二個是延遲初始化。若是是延遲初始化從執行結果上來看和hread.currentThread().getContextClassLoader().loadClass("com.bieber.gc.Main");
是同樣的。<br/> 經過上面能夠理解爲,類的加載分爲兩個步驟:<br/>it
而且能夠獲得父類的加載老是在子類以前,無論是static代碼執行,仍是構造函數的調用。這也很容易理解,由於子類中可能會調用父類的信息,因此先須要將父類準備好了,子類調用的時候,纔沒問題。<br/>io
此處給一個建議:謹慎在父類中定義protected(public) static的屬性,由於這個時候,是全部子類共用一分內存,很容致使讀寫衝突。<br/>
針對上面的測試,下面列舉出幾個其餘的測試,你們看看會獲得什麼結果?
<!-- lang:java --> package com.bieber.gc; public class Field { static{ System.out.println("field static block"); } } public class Main extends Super{ private static Field field=new Field(); public Main() { System.out.println("main init"); } static{ System.out.println("sub static block"); } public void test(){ System.out.println("main test"); } } 或者 public class Main extends Super{ private static Field field; public Main() { System.out.println("main init"); } static{ System.out.println("sub static block"); } public void test(){ System.out.println("main test"); } }
我把Main
類作了上面的調整,看看執行上面的測試用例,會獲得什麼結果。歡迎討論交流,也但願你們也能分享一下大家在開發過程當中的一些東西。