JVM類加載學(xué)習(xí)三-類加載器

JVM類加載器

@(Java)[JVM|類加載器]

類加載過程中的加載階段在JVM的外部實(shí)現(xiàn)。這樣做可以讓應(yīng)用程序自己決定如何去獲取所需要的類。實(shí)現(xiàn)這個(gè)動(dòng)作的代碼模塊就是類加載器

[TOC]

類與類加載器的關(guān)系

對(duì)于任意一個(gè)類,都需要由加載它的類加載器和這個(gè)類本身一同確定該類在JVM中的唯一性。即比較兩個(gè)類是否相等,只有在這兩個(gè)類是由同一個(gè)類加載器加載的前提下才有意義,否則,即使這兩個(gè)類來源于同一個(gè)Class文件,只要加載它們的類加載器不同,那么這兩個(gè)類必定不相等。

  • 這里的“相等”:包括代表類的Class對(duì)象的equals方法、isAssignableFrom方法和isInstance方法的返回結(jié)果,也包括了使用instanceof關(guān)鍵字做對(duì)象所屬關(guān)系判定等情況。
package ThinkingInJVM;

import java.io.IOException;
import java.io.InputStream;
public class ClassLoadTest {
    public static void main(String args[])throws Exception{
        ClassLoader myLoad=new ClassLoader() {
            @Override
            protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
                try {
                    String fileName=name.substring(name.lastIndexOf(".")+1)+".class";
                    InputStream is=getClass().getResourceAsStream(fileName);
                    if (is==null){
                        return super.loadClass(name);
                    }
                    byte[] b=new byte[is.available()];
                    is.read(b);
                    return defineClass(name,b,0,b.length);
                }
                catch (IOException e){
                    throw new ClassNotFoundException();
                }
            }
        };

        Object obj=myLoad.loadClass("ThinkingInJVM.ClassLoadTest").newInstance();

        System.out.println(obj.getClass());
        System.out.println(obj instanceof ThinkingInJVM.ClassLoadTest);
    }
}

在上述代碼中,創(chuàng)建了myLoad對(duì)象,并重寫了類加載器的loadClass方法,構(gòu)造了一個(gè)自定義的類加載器。在最后的比較中,雖然obj.getClass()返回了ThinkingInJVM.ClassLoadTest,但在instanceof的比較中,結(jié)果是false。

  • 這是因?yàn)镴VM中存在兩個(gè)ThinkingInJVM.ClassLoadTest類,一個(gè)是由系統(tǒng)類加載器加載的,另一個(gè)是由自定義的myLoad類加載器加載的。雖然來自同一個(gè)Class文件,但依舊是兩個(gè)獨(dú)立的類。

雙親委派模型

站在JVM的角度,只存在兩種不同的類加載器:

一種是啟動(dòng)類加載器(Bootstrap ClassLoader),是由C++實(shí)現(xiàn),是JVM的一部分。
另外一種是所有其他的類加載器,由Java實(shí)現(xiàn),獨(dú)立于JVM,并且都繼承自java.lang.ClassLoader.

站在開發(fā)人員的角度,可以分為三類:

啟動(dòng)類加載器
擴(kuò)展類加載器
應(yīng)用程序類加載器

Alt text

雙親委派模型:除了頂層的啟動(dòng)類加載器外,其余的類加載器都有自己的父類加載器。這里的父子關(guān)系不是通過繼承實(shí)現(xiàn),而是采用組合的方式復(fù)用父加載器的代碼。

雙親委派模型工作過程

  1. 如果一個(gè)類加載器收到了類加載請(qǐng)求。
  2. 它首先不會(huì)自己去嘗試加載這個(gè)類,而是把這個(gè)請(qǐng)求委派給父類加載器完成。
  3. 每一個(gè)層次的類加載器都是如此,因此所有的加載請(qǐng)求最終都應(yīng)該傳送到頂層的啟動(dòng)類加載器中。
  4. 只有當(dāng)父加載器無法完成這個(gè)加載請(qǐng)求(它的搜索范圍內(nèi)沒有找到所需的類)時(shí),子加載器才會(huì)嘗試自己去加載。

雙親委派模型的特點(diǎn)

  1. Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層次關(guān)系。
  2. 如果沒有使用雙親委派模型,由各個(gè)類加載器自行去加載的話,有可能會(huì)出現(xiàn)由多個(gè)加載器加載的不同的同名類。

雙親委派模型實(shí)現(xiàn)代碼集中在java.lang.ClassLoader的loadClass()方法中。

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;
        }
    }

loadClass()方法執(zhí)行邏輯:

  1. 首先查找是否已經(jīng)被加載。
  2. 若沒有被加載過,則調(diào)用父加載器的loadClass()方法。
  3. 若父加載器為空,則默認(rèn)使用啟動(dòng)類加載器作為父加載器進(jìn)行加載。
  4. 如果上述加載均失敗,則拋出ClassNotFoundException異常,再調(diào)用自己的findClass()方法進(jìn)行加載。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,616評(píng)論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,112評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,355評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,727評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,928評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,165評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評(píng)論 1 282
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,585評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,892評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容

  • 原文鏈接:http://iaspecwang.iteye.com/blog/1931043 一.概述 定義:虛擬機(jī)...
    晴天哥_王志閱讀 6,802評(píng)論 1 35
  • JVM類加載機(jī)制 概述 類加載過程 加載 通過類的全限定名獲取類的二進(jìn)制流 將靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)...
    東溪95閱讀 3,054評(píng)論 0 15
  • 0、前言 讀完本文,你將了解到: 一、為什么說Jabalpur語言是跨平臺(tái)的 二、Java虛擬機(jī)啟動(dòng)、加載類過程分...
    vivi_wong閱讀 1,254評(píng)論 0 10
  • 今夜 我又失眠了 好幾個(gè)夜晚 我都想起那個(gè)影子 如今一個(gè)人的夜晚 讓我像吸毒一樣 上癮的無法自拔 反復(fù)期待白日 等...
    栗春初閱讀 262評(píng)論 17 5
  • 午后調(diào)整好疲憊的身體后,我們來到行程第一站的姐妹廟和皇家公園。這里有高高的雞蛋花樹,草坪上也有墜落的一朵朵,我...
    從爾閱讀 164評(píng)論 0 0