牛客网Java刷题知识点之什么是代码块、普通代码块、静态代码块、同步代码块、构造代码块以及执行顺序...
?
?
不多說,直接上干貨!
?
?
這種形式的程序段我們將其稱之為代碼塊,所謂代碼塊就是用大括號({})將多行代碼封裝在一起,形成一個獨立的數據體,用于實現特定的算法。一般來說代碼塊是不能單獨運行的,它必須要有運行主體。在Java中代碼塊主要分為四種:
public class Test { { //// } }?
?
?
?
?
普通代碼塊
???????普通代碼塊是我們用得最多的也是最普遍的,它就是在方法名后面用{}括起來的代碼段。普通代碼塊是不能夠單獨存在的,它必須要緊跟在方法名后面。同時也必須要使用方法名調用它。
public class Test { public void test(){ System.out.println("普通代碼塊"); } }?
?
?
?
?
?
?靜態代碼塊
???????想到靜態我們就會想到static,靜態代碼塊就是用static修飾的用{}括起來的代碼段,它的主要目的就是對靜態屬性進行初始化。
public class Test { static{ System.out.println("靜態代碼塊"); } }?
?
?
?
?
?同步代碼塊
???????使用 synchronized 關鍵字修飾,并使用“{}”括起來的代碼片段,它表示同一時間只能有一個線程進入到該方法塊中,是一種多線程保護機制。
?
?
?
?
?
?
?
構造代碼塊
???????在類中直接定義沒有任何修飾符、前綴、后綴的代碼塊即為構造代碼塊。我們明白一個類必須至少有一個構造函數,構造函數在生成對象時被調用。構造代碼塊和構造函數一樣同樣是在生成一個對象時被調用,那么構造代碼在什么時候被調用?如何調用的呢?看如下代碼:
public class Test { /** * 構造代碼 */ { System.out.println("執行構造代碼塊..."); } /** * 無參構造函數 */ public Test(){ System.out.println("執行無參構造函數..."); } /** * 有參構造函數 * @param id id */ public Test(String id){ System.out.println("執行有參構造函數..."); } }上面定義了一個非常簡單的類,該類包含無參構造函數、有參構造函數以及構造代碼塊,同時在上面也提過代碼塊是沒有獨立運行的能力,它必須要有一個可以承載的載體,那么編譯器會如何來處理構造代碼塊呢?編譯器會將代碼塊按照他們的順序(假如有多個代碼塊)插入到所有的構造函數的最前端,這樣就能保證不管調用哪個構造函數都會執行所有的構造代碼塊。
?
?
上面代碼等同于如下形式:
public class Test { /** * 無參構造函數 */ public Test(){ System.out.println("執行構造代碼塊..."); System.out.println("執行無參構造函數..."); } /** * 有參構造函數 * @param id id */ public Test(String id){ System.out.println("執行構造代碼塊..."); System.out.println("執行有參構造函數..."); } } 運行結果 public static void main(String[] args) { new Test(); System.out.println("----------------"); new Test("1"); } ------------ Output: 執行構造代碼塊... 執行無參構造函數... ---------------- 執行構造代碼塊... 執行有參構造函數...? ?從上面的運行結果可以看出在new一個對象的時候總是先執行構造代碼,再執行構造函數,但是有一點需要注意構造代碼不是在構造函數之前運行的,它是依托構造函數執行的。正是由于構造代碼塊有這幾個特性,所以它常用于如下場景:
??????1、 初始化實例變量
???????如果一個類中存在若干個構造函數,這些構造函數都需要對實例變量進行初始化,如果我們直接在構造函數中實例化,必定會產生很多重復代碼,繁瑣和可讀性差。這里我們可以充分利用構造代碼塊來實現。這是利用編譯器會將構造代碼塊添加到每個構造函數中的特性。
??????2、 初始化實例環境
???????一個對象必須在適當的場景下才能存在,如果沒有適當的場景,則就需要在創建對象時創建此場景。我們可以利用構造代碼塊來創建此場景,尤其是該場景的創建過程較為復雜。構造代碼會在構造函數之前執行。
???????上面兩個常用場景都充分利用構造代碼塊的特性,能夠很好的解決在實例化對象時構造函數比較難解決的問題,利用構造代碼不僅可以減少代碼量,同時也是程序的可讀性增強了。特別是當一個對象的創建過程比較復雜,需要實現一些復雜邏輯,這個時候如果在構造函數中實現邏輯,這是不推薦的,因為我們提倡構造函數要盡可能的簡單易懂,所以我們可以使用構造代碼封裝這些邏輯實現部分。
?
?
?
靜態代碼塊、構造代碼塊、構造函數執行順序
???????從詞面上我們就可以看出他們的區別。靜態代碼塊,靜態,其作用級別為類,構造代碼塊、構造函數,構造,其作用級別為對象。
???????1、 靜態代碼塊,它是隨著類的加載而被執行,只要類被加載了就會執行,而且只會加載一次,主要用于給類進行初始化。
???????2、 構造代碼塊,每創建一個對象時就會執行一次,且優先于構造函數,主要用于初始化不同對象共性的初始化內容和初始化實例環境。
???????3、 構造函數,每創建一個對象時就會執行一次。同時構造函數是給特定對象進行初始化,而構造代碼是給所有對象進行初始化,作用區域不同。
???????通過上面的分析,他們三者的執行順序應該為:靜態代碼塊 > 構造代碼塊 > 構造函數。
public class Test { /** * 靜態代碼塊 */ static{ System.out.println("執行靜態代碼塊..."); } /** * 構造代碼塊 */ { System.out.println("執行構造代碼塊..."); } /** * 無參構造函數 */ public Test(){ System.out.println("執行無參構造函數..."); } /** * 有參構造函數 * @param id */ public Test(String id){ System.out.println("執行有參構造函數..."); } public static void main(String[] args) { System.out.println("----------------------"); new Test(); System.out.println("----------------------"); new Test("1"); } } ----------- Output: 執行靜態代碼塊... ---------------------- 執行構造代碼塊... 執行無參構造函數... ---------------------- 執行構造代碼塊... 執行有參構造函數...?
?
?
?
?
?
對象的初始化順序:
首先執行父類靜態的內容,父類靜態的內容執行完畢后,接著去執行子類的靜態的內容,當子類的靜態內容執行完畢之后,再去看父類有沒有非靜態代碼塊,如果有就執行父類的非靜態代碼塊,父類的非靜態代碼塊執行完畢,接著執行父類的構造方法;父類的構造方法執行完畢之后,它接著去看子類有沒有非靜態代碼塊,如果有就執行子類的非靜態代碼塊。子類的非靜態代碼塊執行完畢再去執行子類的構造方法。總之一句話,靜態代碼塊內容先執行,接著執行父類非靜態代碼塊和構造方法,然后執行子類非靜態代碼塊和構造方法。
轉載于:https://www.cnblogs.com/zlslch/p/7471029.html
總結
以上是生活随笔為你收集整理的牛客网Java刷题知识点之什么是代码块、普通代码块、静态代码块、同步代码块、构造代码块以及执行顺序...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (Mysql)连接问题之1130
- 下一篇: 在mac上搭建了Java 环境,谨以此文