Java中的靜態(tài)代碼塊與構(gòu)造代碼塊詳解
1、靜態(tài)代碼塊
1. 底層原理
靜態(tài)代碼塊在類的字節(jié)碼被加載到JVM時執(zhí)行,并且在整個JVM生命周期中只會執(zhí)行一次。
JVM在加載類時,先加載類的字節(jié)碼,接著在類中查找靜態(tài)成員和靜態(tài)代碼塊。
所有的靜態(tài)代碼塊會按照它們在類中定義的順序依次執(zhí)行。
2. 執(zhí)行時機
靜態(tài)代碼塊的執(zhí)行時機是在類加載過程中。類加載通常發(fā)生在以下情況之一時:
- 類的第一個實例被創(chuàng)建。
- 訪問類的第一個靜態(tài)成員(靜態(tài)變量或靜態(tài)方法)。
- 使用反射機制來加載類。
當(dāng)滿足上述任一條件時,JVM會加載該類,并執(zhí)行類中的所有靜態(tài)代碼塊。
3. 作用
- 初始化靜態(tài)變量:可以在靜態(tài)代碼塊中對靜態(tài)變量進行復(fù)雜的初始化操作。
- 執(zhí)行一次性設(shè)置:比如加載配置文件、初始化數(shù)據(jù)庫連接池等,僅需要在類加載時執(zhí)行一次的操作。
- 用于捕捉類的加載時間點:有時我們希望在類加載時執(zhí)行某些邏輯,靜態(tài)代碼塊是一個非常合適的地方。
4. 示例
public class StaticBlock { static { System.out.println("靜態(tài)代碼塊 1 被執(zhí)行。"); } static int staticVar = initStaticVar(); static { System.out.println("靜態(tài)代碼塊 2 被執(zhí)行。"); } private static int initStaticVar() { System.out.println("靜態(tài)變量被初始化。"); return 1024; } public static void main(String[] args) { System.out.println("主方法被執(zhí)行。"); System.out.println("靜態(tài)變量staticVar的值為: " + staticVar); } }
運行結(jié)果為:
靜態(tài)代碼塊 1 被執(zhí)行。
靜態(tài)變量被初始化。
靜態(tài)代碼塊 2 被執(zhí)行。
主方法被執(zhí)行。
靜態(tài)變量staticVar的值為: 1024
在這個示例中:
- 靜態(tài)代碼塊按照它們在類中定義的順序執(zhí)行。
- 靜態(tài)變量
staticVar
的初始化發(fā)生在第一個靜態(tài)代碼塊和第二個靜態(tài)代碼塊之間。 - 這些操作只在類首次加載時執(zhí)行一次。
2、構(gòu)造代碼塊
1. 底層原理
構(gòu)造代碼塊是在每次創(chuàng)建對象時執(zhí)行的。JVM在構(gòu)造對象的過程中,會在調(diào)用構(gòu)造方法之前執(zhí)行構(gòu)造代碼塊。
構(gòu)造代碼塊可以用于在對象創(chuàng)建時對實例變量進行初始化,或者執(zhí)行一些在每次創(chuàng)建對象時需要執(zhí)行的代碼。
2. 執(zhí)行時機
每次創(chuàng)建對象時,JVM首先會在堆內(nèi)存中分配對象的內(nèi)存,然后按照以下步驟執(zhí)行:
- 初始化實例變量為默認(rèn)值。
- 執(zhí)行構(gòu)造代碼塊,按它們在類中定義的順序執(zhí)行。
- 執(zhí)行構(gòu)造方法。
因此,構(gòu)造代碼塊的執(zhí)行是在構(gòu)造方法之前的,即使在構(gòu)造方法中進行實例變量的賦值,構(gòu)造代碼塊中的代碼也會先于這些操作執(zhí)行。
3. 作用
- 實例變量的復(fù)雜初始化:構(gòu)造代碼塊適合用來進行實例變量的復(fù)雜初始化操作,尤其是當(dāng)初始化邏輯需要在多個構(gòu)造方法中共享時。
- 每次創(chuàng)建對象時執(zhí)行的邏輯:構(gòu)造代碼塊中的代碼每次創(chuàng)建對象時都會執(zhí)行,所以可以用來在對象創(chuàng)建時執(zhí)行一些公共的邏輯。
4. 示例
public class ConstructBlock { { System.out.println("構(gòu)造代碼塊 1 被執(zhí)行。"); } int constructVar = initConstructVar(); { System.out.println("構(gòu)造代碼塊 2 被執(zhí)行。"); } private int initConstructVar() { System.out.println("成員變量被初始化。"); return 1024; } public ConstructBlock() { System.out.println("構(gòu)造方法被執(zhí)行。"); } public static void main(String[] args) { System.out.println("創(chuàng)建第一個對象:"); new ConstructBlock(); System.out.println("\n創(chuàng)建第二個對象:"); new ConstructBlock(); } }
運行結(jié)果為:
創(chuàng)建第一個對象:
構(gòu)造代碼塊 1 被執(zhí)行。
成員變量被初始化。
構(gòu)造代碼塊 2 被執(zhí)行。
構(gòu)造方法被執(zhí)行。創(chuàng)建第二個對象:
構(gòu)造代碼塊 1 被執(zhí)行。
成員變量被初始化。
構(gòu)造代碼塊 2 被執(zhí)行。
構(gòu)造方法被執(zhí)行。
在這個示例中:
- 每次創(chuàng)建對象時,構(gòu)造代碼塊和實例變量的初始化邏輯都會執(zhí)行。
- 無論你調(diào)用哪個構(gòu)造方法,構(gòu)造代碼塊都將被執(zhí)行,從而確保一些邏輯可以在所有構(gòu)造方法執(zhí)行前運行。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
如何使用Resttemplate和Ribbon調(diào)用Eureka實現(xiàn)負(fù)載均衡
這篇文章主要介紹了如何使用Resttemplate和Ribbon調(diào)用Eureka實現(xiàn)負(fù)載均衡,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03spring cloud config分布式配置中心的高可用問題
本文給大家介紹spring cloud config分布式配置中心的高可用問題,通過整合Eureka來實現(xiàn)配置中心的高可用,需要的朋友參考下本文2018-01-01springboot 設(shè)置server.port不生效的原因及解決
這篇文章主要介紹了springboot 設(shè)置server.port不生效的原因及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08淺談Ribbon、Feign和OpenFeign的區(qū)別
這篇文章主要介紹了淺談Ribbon、Feign和OpenFeign的區(qū)別。具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Spring Boot 集成Shiro的多realm配置過程
這篇文章主要介紹了Spring Boot 集成Shiro的多realm配置,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10jvm垃圾回收GC調(diào)優(yōu)基礎(chǔ)原理分析
談到調(diào)優(yōu),這一定是針對特定場景、特定目的的事情, 對于 GC 調(diào)優(yōu)來說,首先就需要清楚調(diào)優(yōu)的目標(biāo)是什么?從性能的角度看,通常關(guān)注三個方面,內(nèi)存占用(footprint)、延時(latency)和吞吐量(throughput)2022-01-01詳解Java的內(nèi)置異常以及創(chuàng)建自定義異常子類的方法
這篇文章主要介紹了詳解Java的內(nèi)置異常以及創(chuàng)建自定義異常子類的方法,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09安卓系統(tǒng)中實現(xiàn)搖一搖畫面振動效果的方法
這篇文章主要介紹了安卓系統(tǒng)中實現(xiàn)搖一搖畫面振動效果的方法,調(diào)用Android SDK中的SensorEventListener接口,需要的朋友可以參考下2015-07-07SpringBoot參數(shù)校驗之@Valid的使用詳解
這篇文章主要通過示例為大家詳細(xì)介紹一下介紹了SpringBoot參數(shù)校驗中@Valid的使用方法,文中的示例代碼講解詳細(xì),需要的可以參考一下2022-06-06