Java---類加載機制,構造方法,靜態變量,(靜態)代碼塊,父類,變量加載順序


直接上代碼:

代碼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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM