Java執行順序大揭秘:靜態塊、非靜態塊和構造方法誰先誰后?
Hello大家好,我是小米!今天咱們來聊聊Java中的一個小而重要的知識點——初始化塊。可能有的小伙伴一聽這名字就覺得有點頭大,這東西到底是干嘛的?為啥面試官總愛問它?別急,今天我會帶大家從原理到實戰,一次性搞懂靜態初始化塊和非靜態初始化塊的執行順序、優先級和用法,讓面試官忍不住點頭!
什么是初始化塊?
在Java中,初始化塊(Initialization Block)是一段可以在類中定義的代碼,用于在創建對象時執行某些特定的操作。根據是否帶有static關鍵字,可以分為:
- 靜態初始化塊(Static Initialization Block):用static關鍵字聲明,只會在類加載時執行一次。
- 非靜態初始化塊(Instance Initialization Block):沒有static關鍵字,每次創建對象時都會執行。
先別急著覺得難,初始化塊其實是Java中比較常見的用法,尤其是在需要初始化一些復雜的邏輯或共享資源時非常方便。我們從頭開始了解它們的執行順序和用法!
靜態初始化塊:優先級最高的初始化塊
1. 靜態初始化塊是什么?
靜態初始化塊,是由static關鍵字修飾的一段代碼。它的特性有:
- 只執行一次:因為它是在類加載時執行的,所以整個類生命周期中只會執行一次。
- 優先級最高:靜態初始化塊是類第一次加載時最先執行的,甚至在main方法之前。
- 共享性強:由于它只執行一次,所以適合用來初始化類級別的資源,比如靜態變量。
我們來看一個簡單的例子:
圖片
運行這段代碼,你會看到輸出結果為:
圖片
看到沒?靜態初始化塊在main方法之前執行!這是因為Java在執行代碼前,必須先加載類,而靜態初始化塊在類加載時就會執行,這也就是為什么它的優先級最高。
2. 靜態初始化塊的實際應用場景
靜態初始化塊通常用于初始化一些需要在類加載時完成的邏輯,比如:
- 靜態變量的初始化:在塊中對靜態變量進行一些復雜的計算或邏輯操作。
- 初始化共享資源:比如數據庫連接池、文件資源等,這些資源只需要創建一次即可共享。
例如,假設我們有一個數據庫連接池:
圖片
在這個例子中,數據庫連接只需要創建一次,這樣可以確保每次調用getConnection時都能拿到已經初始化好的連接。
非靜態初始化塊:每次創建對象時執行
接下來我們說說非靜態初始化塊。它沒有static關鍵字,每次創建對象時都會被調用。非靜態初始化塊的執行順序是在構造方法之前,但在靜態初始化塊之后。
1. 非靜態初始化塊是什么?
非靜態初始化塊和靜態初始化塊的區別在于:
- 每次創建對象時都會執行:只要你new一個對象,非靜態初始化塊就會執行一次。
- 優先級低于靜態初始化塊:靜態塊會最先執行,接著才是非靜態塊。
來看下面的例子:
圖片
輸出結果為:
圖片
這里可以看到執行順序是:
- 靜態初始化塊
- main方法開始
- 非靜態初始化塊
- 構造方法
- main方法結束
2. 非靜態初始化塊的實際應用場景
非靜態初始化塊通常用來初始化實例變量,或者是對對象進行一些準備操作。比如:
圖片
運行這段代碼會輸出:
圖片
每創建一個User對象,非靜態初始化塊都會執行一次,用于初始化默認的age屬性,這樣每個對象的age值都默認是18。
總結一下執行順序
到這里,我們對靜態初始化塊和非靜態初始化塊的執行順序已經有了清晰的了解,最終的執行順序如下:
- 靜態初始化塊:在類加載時執行,只執行一次。
- 非靜態初始化塊:在對象創建時執行,每次創建對象都會執行。
- 構造方法:緊隨非靜態初始化塊之后,構造方法會執行。
我們可以用這張圖來幫助記憶:
圖片
什么時候用靜態初始化塊和非靜態初始化塊?
靜態初始化塊
- 適用于需要類級別的初始化邏輯,比如初始化靜態變量、共享資源。
- 執行一次的操作,可以放在靜態初始化塊中,確保不會重復執行。
非靜態初始化塊
- 適用于對象級別的初始化邏輯,比如初始化實例變量。
- 每次創建對象都要執行的操作,可以放在非靜態初始化塊中。