java static 块 时机_java的static块执行时机
之前一直認(rèn)為static塊是在class load的時(shí)候執(zhí)行,今天在驗(yàn)證Spring初始化Context loader的時(shí)候,發(fā)現(xiàn)bean的static塊并沒有執(zhí)行。
Class A{
static{
System.out.println("static block invoked!")
}
}
那么static塊到底在什么時(shí)候運(yùn)行的呢?如果了解JVM原理,我們知道,一個(gè)類的運(yùn)行分為以下步驟:
裝載
連接
初始化
其中裝載階段又三個(gè)基本動(dòng)作組成:
通過類型的完全限定名,產(chǎn)生一個(gè)代表該類型的二進(jìn)制數(shù)據(jù)流
解析這個(gè)二進(jìn)制數(shù)據(jù)流為方法區(qū)內(nèi)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)
創(chuàng)建一個(gè)表示該類型的java.lang.Class類的實(shí)例
另外如果一個(gè)類裝載器在預(yù)先裝載的時(shí)遇到缺失或錯(cuò)誤的class文件,它需要等到程序首次主動(dòng)使用該類時(shí)才報(bào)告錯(cuò)誤。
連接階段又分為三部分:
驗(yàn)證,確認(rèn)類型符合Java語言的語義,檢查各個(gè)類之間的二進(jìn)制兼容性(比如final的類不用擁有子類等),另外還需要進(jìn)行符號(hào)引用的驗(yàn)證。
準(zhǔn)備,Java虛擬機(jī)為類變量分配內(nèi)存,設(shè)置默認(rèn)初始值。
解析(可選的) ,在類型的常量池中尋找類,接口,字段和方法的符號(hào)引用,把這些符號(hào)引用替換成直接引用的過程。
當(dāng)一個(gè)類被主動(dòng)使用時(shí),Java虛擬就會(huì)對(duì)其初始化,如下六種情況為主動(dòng)使用:
當(dāng)創(chuàng)建某個(gè)類的新實(shí)例時(shí)(如通過new或者反射,克隆,反序列化等)
當(dāng)調(diào)用某個(gè)類的靜態(tài)方法時(shí)
當(dāng)使用某個(gè)類或接口的靜態(tài)字段時(shí)
當(dāng)調(diào)用Java API中的某些反射方法時(shí),比如類Class中的方法,或者java.lang.reflect中的類的方法時(shí)
當(dāng)初始化某個(gè)子類時(shí)
當(dāng)虛擬機(jī)啟動(dòng)某個(gè)被標(biāo)明為啟動(dòng)類的類(即包含main方法的那個(gè)類)
Java編譯器會(huì)收集所有的類變量初始化語句和類型的靜態(tài)初始化器,將這些放到一個(gè)特殊的方法中:clinit。
實(shí)際上,static塊的執(zhí)行發(fā)生在“初始化”的階段。初始化階段,jvm主要完成對(duì)靜態(tài)變量的初始化,靜態(tài)塊執(zhí)行等工作。
下面我們看看執(zhí)行static塊的幾種情況:
1、第一次new A()的過程會(huì)打印"";因?yàn)檫@個(gè)過程包括了初始化
2、第一次Class.forName("A")的過程會(huì)打印"";因?yàn)檫@個(gè)過程相當(dāng)于Class.forName("A",true,this.getClass().getClassLoader());
3、第一次Class.forName("A",false,this.getClass().getClassLoader())的過程則不會(huì)打印""。因?yàn)閒alse指明了裝載類的過程中,不進(jìn)行初始化。不初始化則不會(huì)執(zhí)行static塊。
參考資料:深入Java虛擬機(jī)
總結(jié)
以上是生活随笔為你收集整理的java static 块 时机_java的static块执行时机的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python dataframe批量将列
- 下一篇: 服务器 独立显卡 显示不出来,dell服