Java代碼執行順序

閱讀原文:Java代碼執行順序java

程序中代碼執行的順序很是重要,稍有不慎便會是程序運行出錯,那麼我將結合實例來分析代碼中的執行。函數

名詞解釋

首先了解幾個名詞:this

非靜態代碼塊

直接由 { } 包起來的代碼,稱爲非靜態代碼塊

靜態代碼塊

直接由 static { } 包起來的代碼,稱爲靜態代碼塊

形參

好比你定義一個函數void add(int a, int b),這裏的a和b就是形參。
當你進行函數調用的時候,add(1, 2),這裏的1和2就是實參。spa

向前引用

所謂向前引用,就是在定義類、接口、方法、變量以前使用它們。code

成員變量

在類體裏面定義的變量稱爲成員變量;
若是該成員變量有 static 關鍵字修飾,則該成員變量稱爲 靜態變量 或 類變量;
若是該成員變量沒有 static 關鍵字修飾,則該成員變量被稱爲 非靜態變量 或 實例變量。

局部變量

形參、方法內定義的變量、代碼塊中定義的變量,都屬於局部變量。

類變量 (靜態變量)

能夠向前引用
變量屬於類自己
類變量不依賴類的實例,類變量只在初始化時候在方法區中被分配一次空間,不管類的實例被建立幾回,都再也不爲類變量分配空間
經過類的任意一個實例來訪問類變量,底層都將將其轉爲經過類自己來訪問類變量,它們的效果是同樣的
一旦類變量的值被改變,經過類或類的任意一個實例來訪問類變量,獲得的都將是被改變後的值
將在類的初始化以前初始化

實例變量(非靜態變量)

不能向前引用,若是向前引用,則稱爲非法向前引用,這是不容許的
變量屬於類的實例對象
隨着類的實例被建立而分配內存空間

實例演示

public class Parent {
    public int parentNum=0;
    public static int staticParentNum=0;
    
    {
        System.out.println("Parent---執行非靜態代碼塊了1!");
    }
    
    {
        System.out.println("Parent---執行非靜態代碼塊了2!");
    }
    
    static{
        System.out.println("Parent---執行靜態代碼塊了1!");
    }
    
    static{
        System.out.println("Parent---執行靜態代碼塊了2!");
    }

    public Parent(){
        System.out.println("Parent---無參構造函數!");
    }
    public Parent(int parentNum){
        this.parentNum=parentNum;
        System.out.println("Parent---有參構造函數!");
        
    }

    public void ParentMethod(int parentNum){
        this.parentNum=parentNum;
        System.out.println("Parent---非靜態方法/parentNum="+parentNum);
    }
    
    public static void staticParentMethod(int staticParentNum){
        Parent.staticParentNum=staticParentNum;
        System.out.println("Parent---靜態方法/staticParentNum="+staticParentNum);
    }
    
}
public class Child extends Parent{

    public int childNum=0;
    public static int staticChildNum=0;
    
    {
        System.out.println("Child---執行非靜態代碼塊了1!");
    }
    
    {
        System.out.println("Child---執行非靜態代碼塊了2!");
    }
    
    static{
        System.out.println("Child---執行靜態代碼塊了1!");
    }
    
    static{
        System.out.println("Child---執行靜態代碼塊了2!");
    }

    public Child(){
        super();
        System.out.println("Child---無參構造函數!");
    }
    
    public Child(int childNum){
        super(childNum);
        System.out.println("Child---有參構造函數!");
    }
    
    public void childMethod(int childNum){
        this.childNum=childNum;
        System.out.println("Child--非靜態方法/childNum="+childNum);
    }
    
    public static void staticChildMethod(int staticChildNum){
        Child.staticChildNum=staticChildNum;
        System.out.println("Child---靜態方法/staticChildNum="+staticChildNum);
    }

    
}
package test;

public class Test {

//    static{
//        System.out.println("Test---靜態代碼塊!");
//    }
    public static void main(String[] args) {
        int key=10;
        switch (key) {
        case 0:
            Parent parent=new Parent();
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Parent---執行非靜態代碼塊了1!
//            Parent---執行非靜態代碼塊了2!
//            Parent---無參構造函數!
//          說明:先加載靜態代碼塊,後加載非靜態代碼塊
        case 1:
            Child b= new Child();
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Child---執行靜態代碼塊了1!
//            Child---執行靜態代碼塊了2!
//            Parent---執行非靜態代碼塊了1!
//            Parent---執行非靜態代碼塊了2!
//            Parent---無參構造函數!
//            Child---執行非靜態代碼塊了1!
//            Child---執行非靜態代碼塊了2!
//            Child---無參構造函數!
//            說明:建立子類,會先執行父類,先執行父類靜態——>子類靜態——>父類非靜態——>父類構造
//——>子類非靜態——>子類構造
        case 2:
            Child c= new Child(4);
            //這個構造函數中指明瞭調用父類的有參構造函數,若不指定,則調用父類無參構造函數
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Child---執行靜態代碼塊了1!
//            Child---執行靜態代碼塊了2!
//            Parent---執行非靜態代碼塊了1!
//            Parent---執行非靜態代碼塊了2!
//            Parent---有參構造函數!
//            Child---執行非靜態代碼塊了1!
//            Child---執行非靜態代碼塊了2!
//            Child---有參構造函數!
            說明:靜態代碼塊或非靜態代碼塊執行順序,按照代碼先後編寫順序。
        case 3:
            Child d= new Child();
            Child e= new Child(4);
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Child---執行靜態代碼塊了1!
//            Child---執行靜態代碼塊了2!
//            Parent---執行非靜態代碼塊了1!
//            Parent---執行非靜態代碼塊了2!
//            Parent---無參構造函數!
//            Child---執行非靜態代碼塊了1!
//            Child---執行非靜態代碼塊了2!
//            Child---無參構造函數!
//            Parent---執行非靜態代碼塊了1!
//            Parent---執行非靜態代碼塊了2!
//            Parent---有參構造函數!
//            Child---執行非靜態代碼塊了1!
//            Child---執行非靜態代碼塊了2!
//            Child---有參構造函數!
            說明:建立多個子類,但父類靜態代碼塊只執行一次。
        case 4:
            Child.staticChildMethod(4);
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Child---執行靜態代碼塊了1!
//            Child---執行靜態代碼塊了2!
//            Child---靜態方法/staticChildNum=4
            說明:靜態方法只能夠調用靜態變量。
        case 5:
            Parent.staticParentMethod(5);
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Parent---靜態方法/staticParentNum=5
            說明:靜態方法可經過 父類名.靜態方法() 調用。
        case 6:
            System.out.println("父類的靜態變量值staticParentNum="+Parent.staticParentNum);
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            父類的靜態變量值staticParentNum=0
            說明:調用靜態變量時,靜態代碼塊會執行。
        case 7:
            System.out.println("子類的靜態變量值staticChildNum="+Child.staticChildNum);
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Child---執行靜態代碼塊了1!
//            Child---執行靜態代碼塊了2!
//            子類的靜態變量值staticChildNum=0
            說明:調用子類靜態變量,父類靜態代碼塊和子類靜態代碼塊會被執行。
        case 8:
            System.out.println("父類的靜態變量值staticParentNum="+Parent.staticParentNum);
            System.out.println("子類的靜態變量值staticChildNum="+Child.staticChildNum);
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            父類的靜態變量值staticParentNum=0
//            Child---執行靜態代碼塊了1!
//            Child---執行靜態代碼塊了2!
//            子類的靜態變量值staticChildNum=0
            
        case 9:
            Child f= new Child();
            f.ParentMethod(3);
            break;
//            Parent---執行靜態代碼塊了1!
//            Parent---執行靜態代碼塊了2!
//            Child---執行靜態代碼塊了1!
//            Child---執行靜態代碼塊了2!
//            Parent---執行非靜態代碼塊了1!
//            Parent---執行非靜態代碼塊了2!
//            Parent---無參構造函數!
//            Child---執行非靜態代碼塊了1!
//            Child---執行非靜態代碼塊了2!
//            Child---無參構造函數!
//            Parent---非靜態方法/parentNum=3
            說明:建立子類,用子類調用父類方法,非靜態方法能夠調用靜態變量。

        default:
            break;
        }

    }

}

總結

  • Java代碼初始化順序
  1. 由 static 關鍵字修飾的(如:類變量(靜態變量)、靜態代碼塊)將在類被初始化建立實例對象以前被初始化,並且是按順序從上到下依次被執行。靜態(類變量、靜態代碼塊)屬於類自己,不依賴於類的實例。
  2. 沒有 static 關鍵字修飾的(如:實例變量(非靜態變量)、非靜態代碼塊)初始化其實是會被提取到類的構造器中被執行的,可是會比類構造器中的代碼塊優先執行到,非靜態(實例變量、非靜態代碼塊)的地位是相等的,它們將按順序被執行。
  • 類變量(靜態變量)、實例變量(非靜態變量)、靜態代碼塊、非靜態代碼塊的初始化時機
  1. 由 static 關鍵字修飾的(如:類變量[靜態變量]、靜態代碼塊)將在類被初始化建立實例對象以前被初始化,並且是按順序從上到下依次被執行;
  2. 沒有 static 關鍵字修飾的(如:實例變量[非靜態變量]、非靜態代碼塊)初始化其實是會被提取到類的構造器中被執行的,可是會比類構造器中的 代碼塊優先執行到,其也是按順序從上到下依次被執行。
  • 容易混淆的一個知識點
    靜態方法只容許直接訪問靜態成員,而實例方法中能夠訪問靜態成員和實例成員,緣由是類尚未實例化,所實例成員也沒有被建立,靜態方法中所以也不能用this。

歡迎關注公衆號交流!
更多關注對象

相關文章
相關標籤/搜索