java 类的加载、连接和初始化
JVM和類
調(diào)用Java命令運行Java程序時,該命令將會啟動一條Java虛擬機(jī)進(jìn)程,不管該Java程序啟動了多少條線程,創(chuàng)建了多少個變量,它們都處于該Java虛擬機(jī)進(jìn)程里,共享該JVM進(jìn)程的內(nèi)存區(qū)。當(dāng)系統(tǒng)出現(xiàn)以下幾種情況時,JVM進(jìn)程將被終止:
- 程序運行到最后正常結(jié)束;
- 程序運行到使用System.exit()或Runtime.getRuntime.exit()代碼結(jié)束程序;
- 程序運行過程中遇到未捕獲的異常或錯誤而結(jié)束;
- 程序所在的平臺強(qiáng)制結(jié)束了JVM進(jìn)程。
類的加載
當(dāng)程序主動使用某個類時,如果該類還沒有被加載到內(nèi)存中,系統(tǒng)會通過加載、連接、初始化這三個步驟來對該類進(jìn)行初始化(如果沒有意外,JVM將會連續(xù)完成這三個步驟,所以有時也會把這三個步驟統(tǒng)稱為類的加載或初始化)。
類的加載是指將類的class文件讀入內(nèi)存,并為之創(chuàng)建一個java.lang.Class對象(注意并不是目標(biāo)類的對象)。也就是說當(dāng)程序中使用任何類時都會為之創(chuàng)建一個java.lang.Class對象。
類的加載由類加載器完成,類加載器通常由JVM提供,這些類加載器也是Java程序運行的基礎(chǔ),JVM提供的這些類加載器通常被稱為系統(tǒng)類加載器。除此之外,開發(fā)者可以通過繼承ClassLoader基類來創(chuàng)建自己的類加載器。
通過使用不同的類加載器,可以從不同來源加載類的二進(jìn)制數(shù)據(jù),通常有如下幾種數(shù)據(jù)來源:
- 從本地文件系統(tǒng)加載class文件;
- 從jar包中加載class文件;
- 通過網(wǎng)絡(luò)加載class文件;
- 把一個Java源文件執(zhí)行動態(tài)編譯,并執(zhí)行加載。
java通常無需等到“首次使用”該類時才加載該類,Java虛擬機(jī)允許系統(tǒng)預(yù)先加載某些類。
類的連接
當(dāng)類被加載后,系統(tǒng)會為之生成一個對應(yīng)的Class對象,接著就會進(jìn)入類的連接階段。
類的連接階段負(fù)責(zé)把類的二進(jìn)制數(shù)據(jù)合并到JRE中。類的連接又可以分為如下三個階段:
- 驗證:驗證階段用于檢驗被加載的類是否有正確的內(nèi)部結(jié)構(gòu),并和其他類協(xié)調(diào)一致;
- 準(zhǔn)備:類的準(zhǔn)備階段則負(fù)責(zé)為類的靜態(tài)屬性分配內(nèi)存,并設(shè)置默認(rèn)初始值;
- 解析:將類的二進(jìn)制數(shù)據(jù)中的符號引用替換成直接引用。(關(guān)于符號引用和直接引用我覺得這里說的非常明白)
類的初始化
在類的初始化階段,虛擬機(jī)負(fù)責(zé)對類進(jìn)行初始化,主要是對靜態(tài)屬性進(jìn)行初始化。在java類中對靜態(tài)屬性進(jìn)行初始化有兩種方式:
- 聲明靜態(tài)屬性時指定初始值;
- 使用靜態(tài)初始化塊為靜態(tài)屬性指定初始值。
進(jìn)行初始化時,JVM會按語句在程序中的排列順序依次執(zhí)行初始化。如下面的代碼,最終b的值為9。
package com.zhyea.test;public class Test {static{b=6;}static int a = 0;static int b = 9;}JVM對類進(jìn)行初始化時包含如下步驟:
- 假如這個類還沒有被加載和連接,程序先執(zhí)行加載并連接這個類;
- 假如該類的直接父類還沒有被初始化,則先初始化其直接父類;
- 假如類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句。
根據(jù)如上步驟可以看出來,當(dāng)程序主動使用任何一個類時,系統(tǒng)會保證該類以及所有父類都會被初始化。
類初始化的時間
系統(tǒng)開始初始化類或接口的時間包括一下6種情況:
- 創(chuàng)建類的實例;
- 調(diào)用某個類的靜態(tài)方法;
- 訪問某個類或接口的靜態(tài)屬性,或為該靜態(tài)屬性賦值;
- 通過反射方式來創(chuàng)建某個類或接口對應(yīng)的java.lang.Class對象,如使用Class.forName(“Person”);
- 初始化某個類的子類。初始化子類時,所有的父類都會被初始化;
- 直接使用java命令來運行某個類時。
需要一提的是final修飾的靜態(tài)屬性,如final修飾的靜態(tài)屬性在編譯時就得到了屬性值,那么該靜態(tài)屬性就會被當(dāng)作常量不會被初始化(類的編譯做了哪些事情呢,這里需要考慮下)。如下面這種情況:
final static int MON = 1;final修飾的靜態(tài)屬性未能在編譯時得到屬性值,那么就會被初始化,如下面這種情況:
final static int TUE = 1+1;還值得一提的就是ClassLoader的loadClass方法并不會執(zhí)行類的初始化,而是只執(zhí)行了類的加載。
轉(zhuǎn)載于:https://www.cnblogs.com/amunote/p/4170627.html
總結(jié)
以上是生活随笔為你收集整理的java 类的加载、连接和初始化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《飞机大战》安卓游戏开发源码(三)
- 下一篇: exec和sp_executesql