程式碼塊與程式碼載入順序

程式碼塊

public class Test {
    {
        ////
    }
}

  這種形式的程式段我們將其稱之為程式碼塊,所謂程式碼塊就是用大括號({ })將多行程式碼封裝在一起,形成一個獨立的資料體,用於實現特定的演算法。一般來說程式碼塊是不能單獨執行的,它必須要有執行主體。在Java中程式碼塊主要分為一下幾種:

1.普通程式碼塊

  普通程式碼塊是我們用得最多的也是最普遍的,它就是在方法名後面用{ }括起來的程式碼段。普通程式碼塊是不能夠單獨存在的,它必須要緊跟在方法名後面。同時也必須要使用方法名呼叫它

public class Test {
    public void test(){
        System.out.println("普通程式碼塊");
    }
}

2.靜態程式碼塊

  想到靜態我們就會想到static,靜態程式碼塊就是用static修飾的用{ }括起來的程式碼段,它的主要目的就是對靜態屬性進行初始化。

public class Test {
    static{
        System.out.println("靜態程式碼塊");
    }
}

3.同步程式碼塊

  使用 synchronized 關鍵字修飾,並使用“{ }”括起來的程式碼片段,它表示同一時間只能有一個執行緒進入到該方法塊中,是一種多執行緒保護機制。

4.構造程式碼塊

  在類中直接定義沒有任何修飾符、字首、字尾的程式碼塊即為構造程式碼塊。我們明白一個類必須至少有一個建構函式,建構函式在生成物件時被呼叫。構造程式碼塊和建構函式一樣同樣是在生成一個物件時被呼叫,那麼構造程式碼在什麼時候被呼叫?如何呼叫的呢?看如下程式碼:

public class Test {
    /**
     * 構造程式碼
     */
    {
        System.out.println("執行構造程式碼塊...");
    }
    
    /**
     * 無參建構函式
     */
    public Test(){
        System.out.println("執行無參建構函式...");
    }
    
    /**
     * 有參建構函式
     * @param id  id
     */
    public Test(String id){
        System.out.println("執行有參建構函式...");
    }
}

  new一個物件的時候總是先執行構造程式碼,再執行建構函式,但是有一點需要注意構造程式碼不是在建構函式之前執行的,它是依託建構函式執行的。正是由於構造程式碼塊有這幾個特性。
  如果一個類中存在若干個建構函式,這些建構函式都需要對例項變數進行初始化,如果我們直接在建構函式中例項化,必定會產生很多重複程式碼,繁瑣和可讀性差。這裡我們可以充分利用構造程式碼塊來實現。這是利用編譯器會將構造程式碼塊新增到每個建構函式中的特性。

public class A {
	int i = 1;
	int initValue;//成員變數的初始化交給程式碼塊來完成
	{
	    //程式碼塊的作用體現於此:在呼叫構造方法之前,用某段程式碼對成員變數進行初始化。
	    //而不是在構造方法呼叫時再進行。一般用於將構造方法的相同部分提取出來。
	    //
	    for (int i = 0;i < 100;i ++) {
	        initValue += i;
	    }
	}
	{
	    System.out.println(initValue);//4950
	    System.out.println(i);//此時會列印i=1
	    int i = 2;//程式碼塊裡的變數和成員變數不衝突,但會優先使用程式碼塊的變數
	    System.out.println(i);//此時列印i=2
	    //System.out.println(j);//提示非法向後引用,因為此時j的的初始化還沒開始。
	    //
	}
	{
	    System.out.println("程式碼塊執行");//程式碼塊執行
	}
	int j = 2;
	{
	    System.out.println(j);//j=2
	    System.out.println(i);//i=1 程式碼塊中的變數執行後自動釋放,不會影響程式碼塊之外的程式碼
	}
	A(){
	    System.out.println("構造方法執行");//構造方法執行
	}
}

5.區域性程式碼塊(補充)

位置:區域性位置(方法內部)
作用:限定變數的生命週期,儘早釋放,節約記憶體
呼叫:呼叫其所在的方法時執行

 public class 區域性程式碼塊 {
@Test
public void test (){
    B b = new B();
    b.go();
}
}
class B {
    B(){}
    public void go() {
        //方法中的區域性程式碼塊,一般進行一次性地呼叫,呼叫完立刻釋放空間,避免在接下來的呼叫過程中佔用棧空間
        //因為棧空間記憶體是有限的,方法呼叫可能會會生成很多區域性變數導致棧記憶體不足。
        //使用區域性程式碼塊可以避免這樣的情況發生。
        {
            int i = 1;
            ArrayList<Integer> list = new ArrayList<>();
            while (i < 1000) {
                list.add(i ++);
            }
            for (Integer j : list) {
                System.out.println(j);
            }
            System.out.println("gogogo");
        }
        System.out.println("hello");
    }
}
--------------------- 
作者:How 2 Play Life 
來源:CSDN 
原文:https://blog.csdn.net/a724888/article/details/80069472 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

程式碼塊載入順序

  1. 靜態程式碼塊它是隨著類的載入而被執行,只要類被載入了就會執行,而且只會載入一次,主要用於給類進行初始化。
  2. 構造程式碼塊每建立一個物件時就會執行一次,且優先於建構函式,主要用於初始化不同物件共性的初始化內容和初始化例項環境。
  3. 建構函式,每建立一個物件時就會執行一次。同時建構函式是給特定物件進行初始化,而構造程式碼是給所有物件進行初始化,作用區域不同。
    通過上面的分析,他們三者的執行順序應該為:靜態程式碼塊 > 構造程式碼塊 > 建構函式。
public class 靜態程式碼塊 {

@Test
public void test() {
    C c1 = new C();
    C c2 = new C();
    //結果,靜態程式碼塊只會呼叫一次,類的所有物件共享該程式碼塊
    //一般用於類的全域性資訊初始化
    //靜態程式碼塊呼叫
    //程式碼塊呼叫
    //構造方法呼叫
    //程式碼塊呼叫
    //構造方法呼叫
}

}
class C{
    C(){
        System.out.println("構造方法呼叫");
    }
    {
        System.out.println("程式碼塊呼叫");
    }
    static {
        System.out.println("靜態程式碼塊呼叫");
    }
}
--------------------- 
作者:How 2 Play Life 
來源:CSDN 
原文:https://blog.csdn.net/a724888/article/details/80069472 
版權宣告:本文為博主原創文章,轉載請附上博文連結!