java 中 bean 的生命周期
本篇中會(huì)對(duì)涉及到的知識(shí)點(diǎn)皆做出描述:
首先,我們先了解先虛擬機(jī)的類加載機(jī)制:
?虛擬機(jī)把描述類的數(shù)據(jù)從Class 文件中加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機(jī)直接使用的 java 類型,這便是虛擬機(jī)的類加載機(jī)制。
也就是說,一個(gè)文本.java 文件要運(yùn)行起來:它首先要經(jīng)過編譯成為 Class 文件(字節(jié)碼文件),然后被虛擬機(jī)加載讀入內(nèi)存,接著虛擬機(jī)首先對(duì)其中的數(shù)據(jù)進(jìn)行校驗(yàn)
?
一個(gè)類從被加載的虛擬機(jī)內(nèi)存中開始到卸載出內(nèi)存為止(java 類的卸載并不能人為主動(dòng)卸載,只能通過 JVM 的垃圾回收來卸載。沒有像 C 中析構(gòu)函數(shù)那樣的東西)經(jīng)歷的有:
加載
加載階段虛擬機(jī)完成三件事情:
1.通過一個(gè)類的全限定名稱來獲取定義此類的二進(jìn)制字節(jié)流
2.將這個(gè)字節(jié)流所代表的靜態(tài)儲(chǔ)存結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
3.在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口
驗(yàn)證
驗(yàn)證階段大致完成4個(gè)階段的檢驗(yàn)動(dòng)作:
1.文件格式驗(yàn)證
該驗(yàn)證階段時(shí)基于二進(jìn)制字節(jié)流的,通過這個(gè)階段驗(yàn)證后字節(jié)流才會(huì)進(jìn)入內(nèi)存的方法區(qū)中進(jìn)行存儲(chǔ)。而后面的3個(gè)驗(yàn)證階段全部是基于方法區(qū)的存儲(chǔ)結(jié)構(gòu)進(jìn)行的。
2.元數(shù)據(jù)驗(yàn)證:比如校驗(yàn)類的繼承關(guān)系是否合法
3.字節(jié)碼驗(yàn)證:例如保證跳轉(zhuǎn)指令不會(huì)跳轉(zhuǎn)到方法體之外的字節(jié)碼指令上。
4.符號(hào)引用驗(yàn)證:例如符號(hào)引用中通過字符串描述的全限定名稱是否能找到對(duì)應(yīng)的類
準(zhǔn)備
正式為類變量分配內(nèi)存并設(shè)置類變量初始值,變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。(這個(gè)時(shí)候進(jìn)行內(nèi)存分配的僅包括類變量既被 static 修飾的變量而不包括實(shí)例變量。實(shí)例變量會(huì)在對(duì)象實(shí)例話時(shí)隨著對(duì)象一起分配在 java 堆中)
這時(shí)分配的初始值往往都時(shí)零值,實(shí)際代碼中定義的值在初始化階段才會(huì)賦予。(final修飾的除外,會(huì)在此階段賦值)
解析
解析階段是將常量池內(nèi)的符號(hào)引用替換為直接引用的過程。
1.類或接口的解析
比如當(dāng)前所在A類,在A類中引用了B類且B類從未被解析過。
(1)如果B不是一個(gè)數(shù)組類型,那虛擬機(jī)會(huì)把代表B的全限定名傳遞給A類的加載器去加載類B。
(2)如果B是一個(gè)數(shù)組類型,并且數(shù)組的元素為對(duì)象。那么虛擬機(jī)會(huì)按(1)中的方式去加載數(shù)組的元素類型。接著虛擬機(jī)會(huì)生成一個(gè)代表此數(shù)組維度和元素的數(shù)組對(duì)象。
(3)如果上面的步驟沒有異常,那么B在虛擬機(jī)中實(shí)際上已經(jīng)成為一個(gè)有效的類或接口了,但在解析完成之前還需進(jìn)行符號(hào)引用驗(yàn)證,確認(rèn)A是否具備對(duì)B的訪問權(quán)限。如不具備則拋出java.lang.IllegalAccessError 非法訪問異常。
2.字段解析
(1)如果A類本身包含了簡(jiǎn)單名稱和字段描述符都與目標(biāo)相匹配的字段,則返回這個(gè)字段的直接引用,查找結(jié)束。
(2)否則,如果在A中實(shí)現(xiàn)了接口,將會(huì)按照繼承關(guān)系從下往上遞歸搜索各個(gè)接口的它的的父接口,如果接口中包含了簡(jiǎn)單名稱和字段描述符都與目標(biāo)相匹配的字段,則返回這個(gè)字段的直接引用,查找結(jié)束。
(3)否則,如果A不是java.lang.Object的話,將會(huì)按照繼承關(guān)系從下往上遞歸搜索其父類。如果在父類中包含了簡(jiǎn)單名稱和字段描述符都與目標(biāo)相匹配的字段,則返回字段查找結(jié)束。
(4)否則,查找失敗。
如果查找成功了還會(huì)對(duì)該字段進(jìn)行權(quán)限驗(yàn)證,如發(fā)現(xiàn)不具備對(duì)字段的訪問權(quán)限,將拋出java.lang.IllegalAccessError異常。
3.類方法解析
4.接口方法解析
初始化
進(jìn)行初始化的條件:
1.當(dāng)遇到 new\getstatic\putstatic\或invokestatic這4調(diào)字節(jié)碼指令時(shí),如沒有進(jìn)行過初始化則需要出發(fā)初始化。
? ? ? ? ? ?既 當(dāng)你用 new 實(shí)例化一個(gè)對(duì)象時(shí) ?讀取或者設(shè)置一個(gè)類的靜態(tài)字段時(shí) (這里有一種靜態(tài)字段除外:用 final 修飾,既已在編譯期把結(jié)果放入常量池的靜態(tài)字段除外) ? 調(diào)用一個(gè)類的靜態(tài)方法的時(shí)候 (同樣,也是被 fianl 修飾的除外)
? ? ? ? ? 總結(jié)來說,第一點(diǎn)就是 當(dāng)用 new 實(shí)例化一個(gè)對(duì)象時(shí) 以及 用到?jīng)]有被 final 修飾的類的靜態(tài)字段或方法時(shí) 就會(huì)觸發(fā)初始化
2.使用 反射包的方法對(duì)類進(jìn)行反射調(diào)用的時(shí)候
? ? ? ? ? ?這個(gè)更好理解,反射調(diào)用類的方法是需要類的實(shí)例的,得到類的實(shí)例便要經(jīng)過初始化過程。
3.當(dāng)初始化一個(gè)類時(shí),如果發(fā)現(xiàn)其父類還未初始化,則要先觸發(fā)其父類的初始化(接口稍有區(qū)別,只有在真正使用到父類接口的時(shí)候才會(huì)去初始化)
4.當(dāng)虛擬機(jī)啟動(dòng)時(shí)會(huì)先初始化主類(既包含main() 方法的那個(gè)類)
5.當(dāng)使用JDK1.7的動(dòng)態(tài)語言支持時(shí)。如果 java.lang.incoke.MethodHandle 實(shí)例最后的解析結(jié)果 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄,并且這個(gè)方法句柄所對(duì)應(yīng)的類沒有進(jìn)行過初始化,則需要先觸發(fā)其初始化。
(了解java.lang.incoke.MethodHandle)
?有且只有這五種情況才會(huì)觸發(fā)初始化。這五種為主動(dòng)引用。除此之外所有引用類的方式都不會(huì)觸發(fā)初始化,這些稱為被動(dòng)引動(dòng)。
一下為被動(dòng)引用:
1.通過子類引用父類的靜態(tài)字段。
2.通過數(shù)組定義來引用類,不會(huì)觸發(fā)此類的初始化
3.常量在編譯階段存入調(diào)用類的常量池中,本質(zhì)上并沒有直接引用到定義常量的類,所以不會(huì)觸發(fā)定義常量的類的初始化。
卸載
這七個(gè)階段。其中,驗(yàn)證、準(zhǔn)備、解析三個(gè)部分又被稱為連接。
?
這幾個(gè)階段的順序:
首先 加載、驗(yàn)證、準(zhǔn)備、初始化和卸載這五個(gè)過程是確定的(使用不用多說)。
1.加載------>2.驗(yàn)證------>3.準(zhǔn)備------->............?初始化.........6.使用------->.7.卸載
既解析和初始化這兩個(gè)的順序是不確定的。某些情況下解析可以在初始化之后再開始,以支持java 的運(yùn)行時(shí)綁定,既動(dòng)態(tài)綁定。(而動(dòng)態(tài)綁定最為容易想到的例子就是多態(tài))所以,可以說java 多態(tài)也是因?yàn)榻馕霾襟E可以在初始化之后。
而確定的這五個(gè)過程也并不是等一個(gè)完成才進(jìn)行下一個(gè)的,這些階段通常都是互相交叉混合的進(jìn)行的,通常會(huì)在一個(gè)階段執(zhí)行的過程中調(diào)用、激活另一個(gè)階段。
?
posted on 2018-03-21 21:23?code前行 閱讀(...) 評(píng)論(...) 編輯 收藏轉(zhuǎn)載于:https://www.cnblogs.com/codefeng/p/8598050.html
總結(jié)
以上是生活随笔為你收集整理的java 中 bean 的生命周期的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LazyT 延迟加载
- 下一篇: MySQL与IO