對ClassLoader的學(xué)習(xí)

ClassLoader是什么?
翻譯過來“類加載器”,將JAVA類加載到JVM中去仰美。


加載 找到對應(yīng)的字節(jié)碼文件(.class)
連接 將字節(jié)碼文件中類的信息讀取到JVM中
初始化 對class文件做相應(yīng)的初始化
使用 JVM對其使用
那么ClassLoader要做的是什么事情妻率?


通過查找中文API找到這個類,上面是這樣說的:
類加載器是負(fù)責(zé)加載類的對象。ClassLoader類是一個抽象類绪妹。如果給定類的二進(jìn)制名稱甥桂,那么類加載器會試圖查找或生成構(gòu)成類定義的數(shù)據(jù)。一般策略是將名稱轉(zhuǎn)換為某個文件名邮旷,然后從文件系統(tǒng)讀取該名稱的“類文件”黄选。
通過查找ClassLoader的方法看到如下:

簡單的來說就是通過類的名稱,返回對應(yīng)的java.lang.Class類的實例婶肩,具體步驟:


findLoadedClass() 上面也說明了 在已經(jīng)加載的類中去找 如果找到办陷,則返回該類對應(yīng)的class對象,如果沒有找到,則調(diào)用


parent.loadClass(name,false) 字面意思parent類加載器調(diào)用loadClass方法
JVM 默認(rèn)有三個類加載器:
bootstrap classloader(c++寫的存在JVM中 java中不存在這個類)律歼、ExtClassloader民镜、AppClassloader三個。

層次結(jié)構(gòu)如下:
boostrap classloader--->ExtClassloader--->AppClassloader--->用戶自定義類加載器
注意 這并不是繼承關(guān)系险毁!
"parent.loadClass()"如果加載失敗沒有找到則調(diào)用


findBootstrapClassOrNull(name) 意思是通過JVM默認(rèn)的加載器去加載
會按照b--->e--->a依次加載
b---->jre/lib/rt.jar
e---->jre/lib/ext/*.jar
a---->classpath指定的jar包目錄
如果JVM默認(rèn)的類加載器都沒有找到就用調(diào)用


findClass(name) 找到自定義的類加載去加載


這個方法默認(rèn)直接返回 ClassNotFoundException
一般自定義的類加載器需要去重寫這個方法
到此結(jié)束 ClassLoader這個類的主要作用就顯而易見了 就是加載.class返回class類的對象實例


定義一個MyClassLoader
我在D盤放一個PageHelper.java 進(jìn)行編譯生成PageHelper.class

public class MyClassloader extends ClassLoader{

    //需要加載類.class文件的目錄  
    private String classDir;  
    
    public void setClassDir(String classDir) {
        this.classDir = classDir;
    }
    
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        
        byte[] bytes = null;
        try {
            super.findClass(name);
        } catch (ClassNotFoundException e1) {
            File file = new File(classDir+"/"+name+".class");
            try {
                bytes = getClassBytes(file);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(bytes==null) throw e1;
        }
        return defineClass(name, bytes, 0, bytes.length);
    }

    private byte[] getClassBytes(File file) throws IOException{  
        FileInputStream fis = new FileInputStream(file);  
        FileChannel channel = fis.getChannel();  
        ByteArrayOutputStream bos = new ByteArrayOutputStream();  
        WritableByteChannel wbc = Channels.newChannel(bos);  
        ByteBuffer bb = ByteBuffer.allocate(1024);  
          
        while (true){  
            int i = channel.read(bb);  
            if (i == 0 || i == -1)  
            break;  
            bb.flip();  
            wbc.write(bb);  
            bb.clear();  
        }
        wbc.close();
        bos.close();
        channel.close();
        fis.close();
        return bos.toByteArray();  
    }
}

main

MyClassloader my = new MyClassloader();
my.setClassDir("D://");
Class clazz = my.loadClass("com.ssm.common.page.PageHelper");
System.out.println(clazz.newInstance().getClass().getClassLoader());
System.out.println(clazz.newInstance().getClass().getClassLoader().getParent());
System.out.println(clazz.newInstance().getClass().getClassLoader().getParent().getParent());
----->
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742
null
MyClassloader my = new MyClassloader();
my.setClassDir("D://");
Class clazz = Class.forName("PageHelper",true,my);
System.out.println(clazz.newInstance().getClass().getClassLoader());
System.out.println(clazz.newInstance().getClass().getClassLoader().getParent());
System.out.println(clazz.newInstance().getClass().getClassLoader().getParent().getParent());
System.out.println(clazz.newInstance().getClass().getClassLoader().getParent().getParent().getParent());
------>
com.ssm.common.classloader.MyClassloader@15db9742
sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@2626b418
null

Class.forname()是一個靜態(tài)方法
該方法在將Class文件加載到內(nèi)存的同時會執(zhí)行類的初始化制圈,得到的class是已經(jīng)初始化完成的


ClassLoader.loadClass()這是一個實例方法,需要一個ClassLoader對象來調(diào)用該方法
該方法將Class文件加載到內(nèi)存時,并不會執(zhí)行類的初始化,得到的class是還沒有連接的
直到這個類第一次使用時才進(jìn)行初始化.該方法因為需要得到一個ClassLoader對象,所以可以根據(jù)需要指定使用哪個類加載器辱揭。這也是節(jié)省內(nèi)存機(jī)制离唐,動態(tài)加載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末问窃,一起剝皮案震驚了整個濱河市亥鬓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌域庇,老刑警劉巖嵌戈,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異听皿,居然都是意外死亡熟呛,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門尉姨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庵朝,“玉大人,你說我怎么就攤上這事又厉【鸥” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵覆致,是天一觀的道長侄旬。 經(jīng)常有香客問我,道長煌妈,這世上最難降的妖魔是什么儡羔? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任宣羊,我火速辦了婚禮,結(jié)果婚禮上汰蜘,老公的妹妹穿的比我還像新娘仇冯。我一直安慰自己,他們只是感情好鉴扫,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布赞枕。 她就那樣靜靜地躺著澈缺,像睡著了一般坪创。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上姐赡,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天莱预,我揣著相機(jī)與錄音,去河邊找鬼项滑。 笑死依沮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枪狂。 我是一名探鬼主播危喉,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼州疾!你這毒婦竟也來了辜限?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤严蓖,失蹤者是張志新(化名)和其女友劉穎薄嫡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颗胡,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡毫深,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了毒姨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哑蔫。...
    茶點(diǎn)故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖弧呐,靈堂內(nèi)的尸體忽然破棺而出闸迷,到底是詐尸還是另有隱情,我是刑警寧澤泉懦,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布稿黍,位于F島的核電站,受9級特大地震影響崩哩,放射性物質(zhì)發(fā)生泄漏巡球。R本人自食惡果不足惜言沐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酣栈。 院中可真熱鬧险胰,春花似錦、人聲如沸矿筝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窖维。三九已至榆综,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铸史,已是汗流浹背鼻疮。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留琳轿,地道東北人判沟。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像崭篡,于是被迫代替她去往敵國和親挪哄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評論 2 361

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