直接上代碼:
代碼1:
public class ConstroctTest { private static ConstroctTest test = new ConstroctTest(); //靜態變量sta1 未賦予初始值 public static int sta1; //靜態變量sta1 賦予初始值20 public static int sta2 = 20; //構造方法中對於靜態變量賦值 private ConstroctTest() { sta1 ++ ; sta2 ++ ; } public static void main(String[] args) { System.out.println(ConstroctTest.sta1); System.out.println(ConstroctTest.sta2); } }
結果:
1
20
代碼2:
public class ConstroctTest { //靜態變量sta1 未賦予初始值 public static int sta1; //靜態變量sta1 賦予初始值20 public static int sta2 = 20; private static ConstroctTest test = new ConstroctTest(); //構造方法中對於靜態變量賦值 private ConstroctTest() { sta1 ++ ; sta2 ++ ; } public static void main(String[] args) { System.out.println(ConstroctTest.sta1); System.out.println(ConstroctTest.sta2); } }
結果:
1
21
結果分析:
1. 按照靜態變量的順序,初始化各靜態變量。(給變量賦予默認值)
2. 按照順序,賦予靜態變量的初始值。
3. 以上結果在於:類靜態變量的位置,決定着通過構造方法給sta1 與 sta2 賦予的值是否有效。
4. 在代碼一中,先對於sta2 執行了 sta2 ++ 操作。而后給sta2 賦予靜態變量值。(只因為順序問題)
代碼3:
public class ConstroctTest { //靜態變量sta1 未賦予初始值 public static int sta1; //靜態變量sta1 賦予初始值20 public static int sta2 = 20; private static ConstroctTest test = new ConstroctTest(); //構造方法中對於靜態變量賦值 private ConstroctTest() { System.out.println("123456"); sta1 ++ ; sta2 ++ ; } public static void main(String[] args) { System.out.println(ConstroctTest.sta1); System.out.println(ConstroctTest.sta2); System.out.println(ConstroctTest.sta1); System.out.println(ConstroctTest.sta1); } }
結果:
結果分析:
1. 從結果可以看出,Java的靜態變量,只是在類第一次加載,初始化的時候執行。
2. 類變量不依賴類的實例,類變量只在初始化時候在棧內存中被分配一次空間,無論類的實例被創建幾次,都不再為類變量分配空間。
3. 可以看出 ,類變量的執行與初始化,與實例對象沒有關系。
代碼4:
public class Test{ public static void main(String[] args){ Child ch = new Child(); } } class Parent{ static String name1 = "hello"; static{ System.out.println("Parent static block"); } public Parent(){ System.out.println("Parent construct block"); } } class Child extends Parent{ static String name2 = "hello"; static{ System.out.println("Child static block"); } public Child(){ System.out.println("Child construct block"); } }
結果:
結果分析:
1. 明先初始化父類的靜態屬性在執行自己的靜態屬性,再是父類的構造方法再是自己的構造方法。
2. 實例化 Child 類。第一要初始化類Child ,因為Child擁有父類(會判斷父類是否初始化),類的初始化只有一次。。初始化類(就是按照順序加載靜態變量與靜態方法)。
3. 初始化Child后。開始實例化Child ,因為擁有父類,所以調用構造方法之前會調用父類的默認構造方法。
代碼5:
public class Animal { private static int k; static{ System.out.println("父類的靜態方法"); } { System.out.println("執行父類的構造代碼塊"); } public Animal(){ System.out.println("執行父類的構造方法"); } public static void main(String[] args) { System.out.println(Animal.k); } }
運行結果:
父類的靜態方法
0
結果分析:
1. 構造代碼塊與構造方法對於類的加載 沒有關系。
代碼6:
public class Animal { private static int k; { System.out.println("執行父類的構造代碼塊"); } static{ System.out.println("父類的靜態方法"); } public Animal(){ System.out.println("執行父類的構造方法"); } public static void main(String[] args) { Animal animal1 = new Animal(); Animal animal2 = new Animal(); } }
結果:
結果分析:
1. 構造代碼塊至於構造方法相關,隨着構造方法的執行而執行。
代碼7:
public class Cat { private static int a; private static int b = 1000; static{ a = 100; b = 200; } public static void main(String[] args) { System.out.println(Cat.a); System.out.println(Cat.b); } }
結果分析:
1. 可以把靜代碼塊中的內容 看做是賦予操作。
2. 當靜態代碼塊在a,b前面。此時輸出的結果是100 1000
代碼8:
package com.fande.amazon.ws.member.rs; class A { static { System.out.println("A的靜態塊"); } private static String staticStr = getStaticStr(); private String str = getStr(); { System.out.println("A的實例塊"); } public A() { System.out.println("A的構造方法"); } private static String getStaticStr() { System.out.println("A的靜態屬性初始化"); return null; } private String getStr() { System.out.println("A的實例屬性初始化"); return null; } public static void main(String[] args) { new B(); new B(); } } class B extends A{ private static String staticStr = getStaticStr(); static { System.out.println("B的靜態塊"); } { System.out.println("B的實例塊"); } public B() { System.out.println("B的構造方法"); } private String str = getStr(); private static String getStaticStr() { System.out.println("B的靜態屬性初始化"); return null; } private String getStr() { System.out.println("B的實例屬性初始化"); return null; } }
通過上面的分析,結果應該很明確了:
由此可見,實例化子類的時候,若此類未被加載過,首先加載是父類的類對象,然后加載子類的類對象,接着實例化父類,最后實例化子類,若此類被加載過,不再加載父類和子類的類對象。
接下來是加載順序,當加載類對象時,首先初始化靜態屬性,然后執行靜態塊;當實例化對象時,首先執行構造塊(直接寫在類中的代碼塊),然后執行構造方法。至於各靜態塊和靜態屬性初始化哪個些執行,是按代碼的先后順序。屬性、構造塊(也就是上面的實例塊)、構造方法之間的執行順序(但構造塊一定會在構造方法前執行),也是按代碼的先后順序。
參考:
http://www.cnblogs.com/maowh/p/3729971.html
http://blog.sina.com.cn/s/blog_68117d6d0102uzbq.html