Java初始化

類初始化

涉及子類初始化時的執行順序

順序以下java

①父類靜態變量和靜態代碼塊(按照聲明順序);shell

②子類靜態變量和靜態代碼塊(按照聲明順序);數組

③父類成員變量和代碼塊(按照聲明順序);code

④父類構造器;對象

⑤子類成員變量和代碼塊(按照聲明順序);源碼

⑥子類構造器。虛擬機

如下源碼來自牛客中的一道題it

class A {
    public A() {
        System.out.println("class A");
    }

    {
        System.out.println("I'm A class"); 
    }

    static {
        System.out.println("class A static"); 
    }
}

public class B extends A {
    public B() {
        System.out.println("class B");
    }

    {
        System.out.println("I'm B class"); 
    }

    static {
        System.out.println("class B static"); 
    }

    public static void main(String[] args) {
        new B();
    }
}

運行結果io

class A static
class B static
I'm A class
class A
I'm B class
class B

在子類初始化時子類涉及重寫父類

在分析上,若是父類即將調用的方法被子類重寫了,那麼父類就會調用子類重寫後的方法,而不會調用父類的方法。編譯

所以牢記,子類重寫父類方法後,調用時會調用子類重寫後的方法

如下源碼來自牛客中的一道題

public class Base 
{
    private String baseName = "base";

    public Base()
    {
        callName();
    }

    public void callName()
    {
        System.out.println(baseName);
    }
    
    static class Sub extends Base 
    {
        private String baseName = "sub";
        public void callName()
        {
            System.out.println(baseName);
        }
    }  
    
    public static void main(String[] args) 
    {  
        Base b = new Sub();
    }
}

運行結果

null

子類實現的方法中調用的baseName爲子類中的私有屬性。

如下源碼來自牛客中的一道題

public class Demo {
    

    class Super 
    {  
        int flag = 1;

        Super() {
            test();
        }  
       
        void test() {
            System.out.println("Super.test() flag=" + flag);
        }
    } 
    

    class Sub extends Super 
    {
        Sub(int i) {  
            flag = i;
            System.out.println("Sub.Sub()flag=" + flag);
        }  
        
        void test() {
            System.out.println("Sub.test()flag=" + flag);
        }
    }  
    

    public static void main(String[] args) 
    {  
        new Demo().new Sub(5);
    }
}

運行結果

Sub.test()flag=1
Sub.Sub()flag=5

主動引用和被動引用

主動引用

JVM規範嚴格規定了有且只有5種狀況必須對類進行「初始化」

  1. 當讀或寫入一個類的靜態變量的時候;當用new實例化對象的時候;當調用一個類的靜態方法的時候
  2. 當使用java.lang.reflect對類進行反射調用的時候,若類未初始化,則須要先觸發其初始化
  3. 初始化一個類的時候,若發現其直接父類沒有被初始化,則去初始化其直接父類。若直接父類向上還有父類未初始化,則繼續向上初始化...
  4. 當JVM啓動時,用戶須要指定一個要執行的主類(就是包含main()方法的那個類),虛擬機會先初始化這個類
  5. 使用JDK1.7動態語言支持的時候的一些狀況。

被動引用

被動引用:除了以上五種以外,其餘的全部引用類的方式都不會觸發初始化。

如下爲被動引用的狀況

經過子類引用父類的的靜態變量,不會致使子類初始化

/**
 * @author mmengyiyu
 */
public class NoInitialization
{
    public static void main(String[] args)
    {
        System.out.println(SubClass.baseStaticIntVar);
    }
}

class Base
{
    static final int baseStaticIntVar = 1;
    static
    {
        System.out.println("Base類的靜態初始化塊...");
    }
}

class SubClass extends Base
{
    static
    {
        System.out.println("SubClass類的靜態初始化塊...");
    }
}

運行結果

1

經過數組定義來引用類,不會觸發此類的初始化

/**
 * @author mmengyiyu
 */
public class NoInitialization
{
    public static void main(String[] args)
    {
        Base[] bases = new Base[5];
        SubClass[] subClasses = new SubClass[5];
    }
}

class Base
{
    static
    {
        System.out.println("Base類的靜態初始化塊...");
    }
}

class SubClass extends Base
{
    static
    {
        System.out.println("SubClass類的靜態初始化塊...");
    }
}

無運行結果

不會觸發類的初始化,天然不可能調用static代碼塊。

常量在編譯階段會存入調用類的常量池中,本質上沒有直接引用到定義常量的類,所以不會觸發定義常量的類的初始化

/**
 * @author mmengyiyu
 */
public class NoInitialization
{
    public static void main(String[] args)
    {
        System.out.println(A.constantIntVar);
    }
}

class A
{
    static
    {
        System.out.println("靜態初始化塊...");
    }
    static final int constantIntVar = 100;
}

運行結果

100
相關文章
相關標籤/搜索