java jvm 加载_Jvm是如何加载Java类的?
前言
我們知道Java語言的類型可以分為兩大類:基本類型「primitive types」和引用類型「reference types」.
對于Java的基本數(shù)據(jù)類型是Java虛擬機(jī)定義好的.至于另一大類「引用數(shù)據(jù)類型」, Java將其分為四種類型:類
接口
數(shù)組
泛型參數(shù)
由于「泛型參數(shù)」在編譯時期會被擦除, 因此Java虛擬機(jī)的類型實(shí)際上只有三種.
在類、接口、數(shù)組當(dāng)中,「數(shù)組」是由Java虛擬機(jī)直接生成的, 類、接口則有對應(yīng)的「字節(jié)流」.
最常見的字節(jié)流則屬于由Java編譯器生成的「class」文件.除此之外我們還可以在程序內(nèi)部生成、直接從網(wǎng)絡(luò)當(dāng)中獲取(如applet)的字節(jié)流.
這此不同形式的「字節(jié)流」都會被加載到Java虛擬機(jī)中, 成為類或者接口.
加載過程
從.class文件中的類到內(nèi)存里的類, 按先后順序需要經(jīng)過加載、鏈接、初始化三個過程.
其中「鏈接過程」當(dāng)中還需要進(jìn)行驗證.
內(nèi)存中的類沒有經(jīng)過初始化,同樣是不能能使用.
加載
「查找」是為了查找字節(jié)流,并且據(jù)此創(chuàng)建類的過程.對于數(shù)組來說,是沒有字節(jié)流的,而是由Java虛擬機(jī)直接生成的對于其它類型來說, Java虛擬機(jī)則需要借助類加載器來完成查找字節(jié)流的的過程.
加載器bootstrapClassLoader(啟動類加載器)最頂層的加載器,由c++實(shí)現(xiàn)
負(fù)責(zé)加載%JAVA_HOME%/lib目錄下的jar包和類,或者被-Xbootclasspath參數(shù)指定的路徑中的所有的類.
2. 擴(kuò)展類加載器「Extension Class Loader」繼承于java.lang.ClassLoader
主要負(fù)責(zé)加載%JAVA_HOME%/lib/ext/下的jar包和類,或者被java.ext.dirs系統(tǒng)變量所指定的路徑下的jar包.
3. 應(yīng)用類加載器「Application Class Loader」繼承于java.lang.ClassLoader
面向用戶的類加載器
負(fù)責(zé)加載當(dāng)前應(yīng)用classpath下的jar和類.
雙親委派模型雙親委派模型每一個類都有它對應(yīng)的類加載器.
系統(tǒng)中的ClassLoader在協(xié)同的時候會默認(rèn)啟用雙親委派模型.
在類加載的過程中,首先會判斷這個類是否被加載過.
被加載過 -> 直接返回
沒有被加載過 -> 嘗試加載
加載流程先把加載類的請求委派給該父類加載器的loadClass進(jìn)行處理.
因此所有的請求最終都應(yīng)該傳送到最頂層的類加載器BootstrapClassLoader中.
當(dāng)父類無法處理時,才需要自己處理.
當(dāng)父類加載器為null時,會使用BootstrapClassLoader作為其父類加載器
雙親委派模型的優(yōu)點(diǎn)保證了java的穩(wěn)定的運(yùn)行, 可以保證類不被重復(fù)加載.
jvm區(qū)分不同的類不僅僅是根據(jù)全類名, 相同的類文件被不同的類加載器加載產(chǎn)生的也是兩個不同的類.
保證java核心api不被修改.
鏈接
將創(chuàng)建的類合成至Java虛擬機(jī)中,使之能夠被執(zhí)行的過程.它可以分為驗證、準(zhǔn)備及解析三個過程.驗證階段的目的是為了確保被加載的類滿足虛擬機(jī)的約束條件.
準(zhǔn)備階段的目的是為了被加載類的字段分配內(nèi)存.
Java代碼中對靜態(tài)字段的具體初始化則會在稍后的初始化階段進(jìn)行.
構(gòu)造其它跟類層次相關(guān)的數(shù)據(jù)結(jié)構(gòu).比如說用來實(shí)現(xiàn)虛方法的動態(tài)綁定的方法表.
解析階段的目的是,將符號引用解析成為實(shí)際引用.
如果符號引用指向一個未被加載的類、或者未被加載類的字段或方法,那么解析將觸發(fā)這個類的加載(但未必觸發(fā)這個類的鏈接以及初始化)
初始化
為標(biāo)記為常量值的字段賦值,以及執(zhí)行方法的過程.
java虛擬機(jī)會通過加鎖來確保類的方法僅被執(zhí)行一次.
只有當(dāng)初始化完成之后,類才正式成為可執(zhí)行狀態(tài).
類的初始化觸發(fā)情況當(dāng)虛擬機(jī)啟動的時候,初始化用戶指定的主類.
當(dāng)遇到用以新建目標(biāo)類實(shí)例的new指令的時候,初始化new指令的目標(biāo)類.
當(dāng)遇到調(diào)用靜態(tài)方法時,初始化該類的靜態(tài)字段.
當(dāng)遇到訪問靜態(tài)字段的指令時,初始化該靜態(tài)字段所在的類.
子類的初始化會觸發(fā)父類的初始化.
如果一個接口定義default方法,那么直接實(shí)現(xiàn)或者間接實(shí)現(xiàn)該接口的類的初始化,會觸發(fā)該接口的初始化.
使用反射api對某個類進(jìn)行反射調(diào)用時,初始化這個類.
當(dāng)初次調(diào)用MethodHandle實(shí)例時,初始化該MethodHandle指向的方法所在的類.
總結(jié)
以上是生活随笔為你收集整理的java jvm 加载_Jvm是如何加载Java类的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英雄无敌3高清 Android,安卓TO
- 下一篇: java 开发详解_面向接口编程详解-J