1. 局部代碼塊:
局部代碼塊定義在方法中,用花括號'{}'包含。例如在method()方法中我們創建一個局部代碼塊。
void method() { { int x = 22; System.out.println("age = " + x); System.out.println("這是一個局部代碼塊"); } }
在上述代碼中,我們可以直接去掉代碼塊的花括號,運行效果和加代碼塊一致。那么,有什么必要使用局部代碼塊嗎?
局部代碼塊可以限制變量的生命周期,也就是說在代碼塊中創建的變量只在代碼塊中有效,當代碼塊運行結束,變量就會被釋放,從而節省內存空間。
具體看一下以下代碼來理解局部代碼塊的釋放變量內存空間。
void method() { int age = 10; { int age = 100; //此處報錯[Duplicate local variable age];去掉前面的int類型聲明即可 } System.out.println("age = " + age); }
首先在局部代碼塊之外定義一個int類型的age變量。然后在局部代碼塊中再次定義一個int類型的age變量,此時報錯說是[重復定義了兩個變量age]。如果我們將上述方法中的局部變量和局部代碼塊交換一下順序會怎么樣呢?
void method() { { int age = 100; } int age = 10; System.out.println("age = " + age); }
可以看到,這樣就不會報錯了,這是因為在代碼塊中使用完變量之后就會釋放掉,所以出了代碼塊,內存中就不再存在age這個變量了。
2. 構造代碼塊:
構造代碼塊是定義在類中方法外的,同樣是用花括號'{}'包含;例如:
public class Test { public Test() { System.out.println("無參構造"); } public Test(int num) { System.out.println("帶參構造"); } { System.out.println("構造代碼塊"); } public static void main(String[] args) { Test test = new Test(); System.out.println("-------------"); Test test2 = new Test(1); } }
之前的代碼塊叫做局部代碼塊是因為它放在方法中,相當於是局部位置。那么此處的構造代碼塊是否和構造方法有着千絲萬縷的聯系呢?
通過上述代碼,我們可以驗證一下,運行結果如下:
[構造代碼塊
無參構造
-------------
構造代碼塊
帶參構造]
可以看出:無論是使用無參構造還是有參構造來創建對象,首先都會執行構造代碼塊中的內容。所以它可以對對象進行初始化;即每個對象都具有的功能可以放在構造代碼塊中,在對象創建時,就會實現該功能,從而減少代碼的冗余度,提高代碼復用性。
3. 靜態代碼塊:
靜態代碼塊同樣是定義在類中的,相對於構造代碼塊,只是在花括號前加了一個static修飾符。同樣的,我們通過代碼來看一下它的作用。
public class StaticTest { public StaticTest() { System.out.println("無參構造"); } public StaticTest(int num) { System.out.println("帶參構造"); } static { System.out.println("靜態代碼塊"); } public static void main(String[] args) { StaticTest st = new StaticTest(); System.out.println("----------------"); StaticTest st2 = new StaticTest(1); } }
運行結果為:
[靜態代碼塊
無參構造
----------------
帶參構造]
可以看到,我們以無參和帶參的形式創建對象,雖然同構造代碼塊一樣,執行在構造方法前面,但是靜態代碼塊僅執行一次。
靜態代碼塊是在類加載時初始化的,隨着類的加載而加載;所以有些代碼必須在項目啟動的時候就執行的話,需要使用靜態代碼塊。
4. 優先級順序:
因為局部代碼塊是需要調用包含局部代碼塊的方法才能得到執行,所以可以比較main()方法、靜態代碼塊、構造代碼塊、構造方法之間的執行順序。
public class YouXianJi { public YouXianJi() { System.out.println("無參構造"); } public YouXianJi(int x) { System.out.println("帶參構造"); } { System.out.println("構造代碼塊"); } static { System.out.println("靜態代碼塊"); } void method() { { System.out.println("局部代碼塊"); } } public static void main(String[] args) { System.out.println("main()方法"); YouXianJi yxJ = new YouXianJi(); // 無參方式創建對象 yxJ.method(); System.out.println("---------------------------------------"); YouXianJi yxji = new YouXianJi(1); // 帶參方式創建對象 yxji.method(); } }
運行結果為:
[靜態代碼塊
main()方法
構造代碼塊
無參構造
局部代碼塊
---------------------------------------
構造代碼塊
帶參構造
局部代碼塊]
所以可以看出來優先執行順序是靜態代碼塊 > main()方法 > 構造代碼塊 > 構造方法。
然后我們再看一下具有繼承關系的子類和父類之間的靜態代碼塊、構造代碼塊、構造方法之間的執行順序。
class Father { public Father() { System.out.println("父類無參構造"); } Father(int num) { System.out.println("父類帶參構造"); } { System.out.println("父類構造代碼塊"); } static { System.out.println("父類靜態代碼塊"); } } class Son extends Father { public Son() { System.out.println("子類無參構造"); } public Son(int num) { System.out.println("子類帶參構造"); } { System.out.println("子類構造代碼塊"); } static { System.out.println("子類靜態代碼塊"); } } public class Init { public static void main(String[] args) { Son son = new Son(); Son son2 = new Son(1); System.out.println("-------------------------"); Father father = new Father(); Father father2 = new Father(1); System.out.println("-------------------------"); Father father3 = new Son(); Father father4 = new Son(1); } }
運行結果如下:
[父類靜態代碼塊
子類靜態代碼塊
父類構造代碼塊
父類無參構造
子類構造代碼塊
子類無參構造
父類構造代碼塊
父類無參構造
子類構造代碼塊
子類帶參構造
-------------------------
父類構造代碼塊
父類無參構造
父類構造代碼塊
父類帶參構造
-------------------------
父類構造代碼塊
父類無參構造
子類構造代碼塊
子類無參構造
父類構造代碼塊
父類無參構造
子類構造代碼塊
子類帶參構造]
所以優先級是父類靜態代碼塊 > 子類靜態代碼塊 > 父類構造代碼塊 > 父類構造方法 > 子類構造代碼塊 > 子類構造方法。