1. 程式人生 > 實用技巧 >Java非靜態程式碼塊和例項初始化過程

Java非靜態程式碼塊和例項初始化過程

1 非靜態程式碼塊

非靜態程式碼塊特點

①可以為例項變數(非靜態的屬性)初始化

②每次建立物件的時候,都會執行一次,且先於構造器執行

③若有多個非靜態的程式碼塊,那麼按照定義的順序從上到下依次執行

④程式碼塊中既可以呼叫非靜態的變數和方法,也可以可以呼叫靜態的變數和方法

測試程式碼:

public class BlockTest {
    public static void main(String[] args) {
        MyClass my1 = new MyClass();
        //MyClass my2 = new MyClass("java");
    }
}

class MyClass {
    private String str;

    {
        System.out.println("非靜態程式碼塊1");
    }

    public MyClass() {
        System.out.println("無參構造");
    }

    public MyClass(String str) {
        this.str = str;
        System.out.println("有參構造");
    }

    {
        System.out.println("非靜態程式碼塊2");
    }
}

執行結果

非靜態程式碼塊1
非靜態程式碼塊2
無參構造

2 例項初始化

例項初始化過程:建立物件時,為物件進行初始化的操作
①為成員變數顯式賦值
②執行非靜態程式碼塊
③執行構造器

Java編譯器會把這三個部分的程式碼,合成一個叫做 <init>([形參列表]) 例項初始化方法
即編譯後的.class位元組碼資訊中,是沒有構造器這個概念。

<init>([形參列表]) 例項初始化方法的程式碼就是由三個部分組成:
①成員變數顯式賦值的程式碼
②非靜態程式碼塊中的程式碼
③構造器中的程式碼

其中①和②按定義順序依次執行,③最後執行。

而且,有幾個構造器,就會有幾個例項初始化方法。那麼當你建立物件的時候,呼叫對應的構造器時,其實執行的是對應的例項初始化方法 <init>([形參列表])

程式碼示例:

public class InitTest {
    public static void main(String[] args) {
        Demo d1 = new Demo();
        //Demo d2 = new Demo("java");
    }
}

class Demo{

    {
        System.out.println("非靜態程式碼塊1");
    }

    private String str = assign();//呼叫方法,為str進行顯式賦值

    public Demo(){
        System.out.println("無參構造");
    }
    public Demo(String str){
        this.str = str;
        System.out.println("有參構造");
    }

    {
        System.out.println("非靜態程式碼塊2");
    }

    public String assign(){
        System.out.println("為成員變數賦值");
        return "hello";
    }
}

3 子類例項初始化

(1)先執行父類的例項初始化方法

它由三部分組成:

  1. 成員變數的顯式賦值

  2. 非靜態程式碼塊

  3. 構造器

(2)再執行子類的例項初始化方法

它由三部分組成:

  1. 成員變數的顯式賦值

  2. 非靜態程式碼塊

  3. 構造器

super()或super(實參列表) 表面是呼叫父類的構造器,其實是呼叫父類對應的例項初始化方法

super()或super(例項列表) 表面是在子類構造器的首行,其實是在子類例項初始化方法的首行

程式碼示例:

public class InitTest2 {
    public static void main(String[] args) {
        Son s = new Son();
    }
}

class Father {
    private String strFather = assignFather();
    
    {
        System.out.println("父類的非靜態程式碼塊");
    }
    
    public Father(){
        System.out.println("父類的無參構造");
    }
    
    public String assignFather(){
        System.out.println("父類的assignFather()");
        return "father";
    }
}

class Son extends Father {
    private String strSon = assignSon();
    
    {
        System.out.println("子類的非靜態程式碼塊");
    }
    
    public Son(){
        //super() ==> 呼叫父類的例項初始化方法,而且它在子類例項初始化方法的首行
        System.out.println("子類的無參構造");
    }

    public String assignSon(){
        System.out.println("子類的assignSon()");
        return "son";
    }
}

執行結果:

父類的assignFather()
父類的非靜態程式碼塊
父類的無參構造
子類的assignSon()
子類的非靜態程式碼塊
子類的無參構造

子類為成員變數顯式賦值方法重寫父類顯式賦值方法時,呼叫的子類重寫的方法,程式碼示例:

public class InitTest3 {
    public static void main(String[] args) {
        Son s = new Son();
    }
}

class Father {
    private String strFu = assign();

    {
        System.out.println("父類的非靜態程式碼塊");
    }

    public Father(){
        System.out.println("父類的無參構造");
    }

    public String assign(){
        System.out.println("父類的assign()");
        return "father";
    }
}

class Son extends Father {
    private String strSon = assign();

    {
        System.out.println("子類的非靜態程式碼塊");
    }

    public Son(){
        //super()  ==>呼叫父類的例項初始化方法,而且它在子類例項初始化方法的首行
        System.out.println("子類的無參構造");
    }

    public String assign(){
        System.out.println("子類的assign()");
        return "son";
    }
}

執行結果:

子類的assign()
父類的非靜態程式碼塊
父類的無參構造
子類的assign()
子類的非靜態程式碼塊
子類的無參構造