Java的類加載機制

類加載過程

類從被加載到虛擬機內存開始器紧,直到被卸載出內存為止,它的整個生命周期過程是:

加載 ---> 驗證 ---> 準備 ---> 解析 ---> 初始化 ---> 使用 ---> 卸載

加載

加載是類加載過程的第一個階段楼眷,在加載階段虛擬機需要完成三件事铲汪。

  1. 通過一個類的全限定名來獲取其定義的二進制字節(jié)流
  2. 將這個字節(jié)流所表示的靜態(tài)存儲結構轉化為方法區(qū)運行時數據結構
  3. 在內存中生成一個代表這個類的class對象熊尉,作為方法區(qū)的各種數據的訪問入口

類加載器

類的加載的全都是交給類加載器去實現的。

在Java虛擬機規(guī)范中掌腰,加載器是分為兩大類:

  1. 引導類加載器

    引導類加載器是使用本地代碼實現的類加載器狰住,負責將<JAVA_HOME>/lib下的核心類庫或-Xbootclasspath選項指定的jar包給加載到內存中。

    這個加載器是屬于虛擬機部分的類齿梁,Java中是無法獲取到的

  2. 自定義加載器

    自定義加載器可以分為三類:

    • 擴展類加載器

      擴展類加載器是負責將<JAVA_HOME>/lib/ext或者由系統(tǒng)變量-Djava.ext.dir指定位置中的類庫加載到內存中

    • 應用程序類加載器

      應用程序類加載器是將classPath中所指定的類催植,一般來說Java類都是由這個類加載器來加載的

    • 自定義類加載器

      除了系統(tǒng)提供的類之外,也可以通過繼承java.lang.ClassLoader類的方式實現自己的類加載器

類的加載順序 ----- 雙親委派模型

他們之間的關系如下圖所示:


image

JVM加載類的時候默認采用的是雙親委派機制士飒,
也是是說在某個類加載器在接收到加載類的請求的時候,
首先是將加載任務委托給父類加載器蔗崎,依次遞歸酵幕,如果父類加載器能夠完成加載就成功返回,
只有當父類加載器無法完成加載任務時候缓苛,才會去調用自己去加載類芳撒。

在JDK中有默認的擴展類加載器和應用程序類加載器

sun.misc.Launcher$ExtClassLoader 和 sun.misc.Launcher$AppClassLoader

可以用代碼看一下他們的加載關系:

public class Main {
    public static void main(String[] args) {
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader().getParent());
        System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
    }
}

運行結果:

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@60e53b93
null

這個運行結果能夠驗證我們之前雙親委派模型的圖,應用程序類加載器調用擴展類加載器最后調用一個訪問不到的引導類加載器

他們的依賴關系:
<figure class="half"> <img src="http://ztianzeng.com/images/Java的類加載機制/yilaiguanxi.jpg" alt="圖片說明" > <img src="http://ztianzeng.com/images/Java的類加載機制/yilaiguanxi2.jpg" alt="圖片說明" > </figure>

他們最后都是調用ClassLoader這個里面的loadClass實現類加載

雙親委派模型的類加載邏輯:

  1. 首先檢查c有沒有被加載
  2. 如果沒有沒加載未桥,查看父類加載器是否為空笔刹,為空調用父類加載器加載,否則調用引導類加載器加載
  3. 如果c在父類加載器加載下沒有加載成功冬耿,會調用當前加載器的findClass進行加載
  4. 若class最終被加載舌菜,且resolve為true,則對該class進行鏈接操作
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

驗證

驗證階段用于確保類或接口的二進制結構上是正確的亦镶。需要滿足Java虛擬機限制中描述的靜態(tài)或者結構上的約束

準備

準備階段的任務是為類或接口的靜態(tài)字段分配空間日月,并用初始值初始化這些字段,這個階段不會執(zhí)行任何的虛擬機字節(jié)碼指令缤骨。
也是就說不會初始化任何實例變量爱咬。

初始值是指Java虛擬機規(guī)范所支持的數據類型和對應的初始值。
比如:

    public static int value = 2绊起;

它最準備階段被賦予的初始值是0而不是2精拟。

在類的對象創(chuàng)建之后的任何時間,都可以進行準備階段虱歪,但它得確保一定要在初始化階段開始前完成蜂绎。

解析

解析是根據運行時常量池的符號引用來動態(tài)決定具體的值的過程。
總共要解析六種類型:

  • 類與接口解析

  • 字段解析

  • 普通方法解析

  • 接口方法解析

  • 方法類型與方法句柄解析

  • 調用點限定符解析

初始化

初始化過程才是虛擬機真正執(zhí)行Java代碼的過程笋鄙。

會觸發(fā)初始化過程的有這幾種行為:

  1. 在被選為Java啟動的初始類
  2. 在對于某個類的子類初始化時
  3. 在調用JDK類庫的反射方法時
  4. 在調用java.lang.invoke.MethodHandle時荡碾,如果檢測出來有static方法時
  5. 在執(zhí)行new方法、初始代碼塊或靜態(tài)代碼塊時

在多線程環(huán)境下局装,虛擬機會保證一個類的初始化方法會被正確的加鎖和同步坛吁。

使用

在初始化完成之后才能夠對類進行調用

卸載

卸載時Java虛擬機將類移出內存的過程劳殖。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拨脉,隨后出現的幾起案子哆姻,更是在濱河造成了極大的恐慌,老刑警劉巖玫膀,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矛缨,死亡現場離奇詭異,居然都是意外死亡帖旨,警方通過查閱死者的電腦和手機箕昭,發(fā)現死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來解阅,“玉大人落竹,你說我怎么就攤上這事』醭” “怎么了述召?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蟹地。 經常有香客問我积暖,道長,這世上最難降的妖魔是什么怪与? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任夺刑,我火速辦了婚禮,結果婚禮上分别,老公的妹妹穿的比我還像新娘性誉。我一直安慰自己,他們只是感情好茎杂,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布错览。 她就那樣靜靜地躺著,像睡著了一般煌往。 火紅的嫁衣襯著肌膚如雪倾哺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天刽脖,我揣著相機與錄音羞海,去河邊找鬼。 笑死曲管,一個胖子當著我的面吹牛却邓,可吹牛的內容都是我干的。 我是一名探鬼主播院水,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼腊徙,長吁一口氣:“原來是場噩夢啊……” “哼简十!你這毒婦竟也來了?” 一聲冷哼從身側響起撬腾,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤螟蝙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后民傻,有當地人在樹林里發(fā)現了一具尸體胰默,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年漓踢,在試婚紗的時候發(fā)現自己被綠了牵署。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡喧半,死狀恐怖奴迅,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情薯酝,我是刑警寧澤半沽,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布爽柒,位于F島的核電站吴菠,受9級特大地震影響,放射性物質發(fā)生泄漏浩村。R本人自食惡果不足惜做葵,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望心墅。 院中可真熱鬧酿矢,春花似錦婴程、人聲如沸膀曾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铐姚。三九已至策肝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間隐绵,已是汗流浹背之众。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留依许,地道東北人棺禾。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像峭跳,于是被迫代替她去往敵國和親膘婶。 傳聞我的和親對象是個殘疾皇子缺前,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容