国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java類加載機(jī)制之雙親委派模型

X_AirDu / 1438人閱讀

摘要:比如我們要加載類,無論我們用哪個(gè)類加載器去加載類,這個(gè)加載請(qǐng)求最終都會(huì)委托給,這樣就保證了所有加載器加載的類都是同一個(gè)類。如果沒有雙親委派模型,那就亂了套了,完全可能搞出多個(gè)不同的類。

前言

雙親委派模型是Java加載類的機(jī)制.采用雙親委派模型的好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級(jí)的層級(jí)關(guān)系,通過這種層級(jí)關(guān)系可以避免類的重復(fù)加載.

1. 模型基礎(chǔ)

Bootstrap ClassLoader(啟動(dòng)類加載器): 負(fù)責(zé)將%JAVA_HOME%/lib目錄中或-Xbootclasspath中參數(shù)指定的路徑中的,并且是虛擬機(jī)識(shí)別的(按名稱)類庫加載到JVM中

Extension ClassLoader(擴(kuò)展類加載器): 負(fù)責(zé)加載%JAVA_HOME%/lib/ext中的所有類庫

Application ClassLoader(應(yīng)用程序加載器): 負(fù)責(zé)ClassPath中的類庫

2. 為什么使用雙親委派模型?

1.雙親委派模型最大的好處就是讓Java類同其類加載器一起具備了一種帶優(yōu)先級(jí)的層次關(guān)系。這句話可能不好理解,我們舉個(gè)例子。比如我們要加載java.lang.Object類,無論我們用哪個(gè)類加載器去加載Object類,這個(gè)加載請(qǐng)求最終都會(huì)委托給Bootstrap ClassLoader,這樣就保證了所有加載器加載的Object類都是同一個(gè)類。如果沒有雙親委派模型,那就亂了套了,完全可能搞出多個(gè)不同的Object類。
2.自上而下每個(gè)類加載器都會(huì)盡力加載.

3. 看看源碼

1.首先加載類調(diào)用的loadClass方法,我們找到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;
        }
    }

首先判斷了該類是否已加載.

若沒加載,則傳給雙親加載器去加載,

若雙親加載器沒能成功加載它,則自己用findClass()去加載.所以是個(gè)向上遞歸的過程.

自定義加載器時(shí),需要重寫findClass方法,因?yàn)槭强盏?沒有任何內(nèi)容:

 protected Class findClass(String name) throws ClassNotFoundException {
        throw new ClassNotFoundException(name);
    }
4. 自己動(dòng)手,編寫一個(gè)自己的類加載器

1.首先需要一個(gè)編譯好的class文件,筆者用了一個(gè)之前寫的斐波那契的類Fib.class(所在路徑:C:/Users/Think/crabapple),下面是用idea通過反編譯方式打開的class文件,注意記下class文件的包名,在后續(xù)代碼中需要使用類的全限定名稱.

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package crabapple;

public class Fib {
  
    public static int fib(int num) {
        return num < 2 ? num : fib(num - 2) + fib(num - 1);
    }
}

2.繼承ClassLoader,重寫findClass方法:

class MyClassLoader extends ClassLoader {
    private String classPath;  // 保存的地址

    /**
     * 傳入地址構(gòu)造函數(shù)
     * @param classPath
     */
    public MyClassLoader(String classPath) {
        this.classPath = classPath;
    }

    /**
     * 讀取class文件
     * @param name
     * @return
     * @throws Exception
     */
    private byte[] loadByte(String name) throws Exception {
        String inPath = classPath + "/" + name + ".class";
        FileInputStream fis = new FileInputStream(inPath);
        int len = fis.available();
        byte[] data = new byte[len];
        fis.read(data);
        fis.close();
        return data;
    }

    /**
     * 重寫findClass方法,讓加載的時(shí)候調(diào)用findClass方法
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    protected Class findClass(String name) throws ClassNotFoundException {
        try {
            byte[] data = loadByte(name);
            // 將字節(jié)碼載入內(nèi)存
            return defineClass(name, data, 0, data.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

loadByte方法僅用作讀取文件

findClass方法才是加載類到內(nèi)存的,注意name必須填全限定名,比如java.lang.Object.

3.測(cè)試,一下將使用一些反射機(jī)制和class類的方法.

public class ClassLoaderTest extends ClassLoader {

    //main函數(shù)本該拋出異常有 ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException,為了好看,簡寫成Exception
    public static void main(String[] args) throws Exception {
        //初始化類加載器
        MyClassLoader myClassLoader=new MyClassLoader("C:/Users/Think/crabapple");
        //加載Fib類,筆者class文件包名為crabapple
        Class myClass=myClassLoader.loadClass("crabapple.Fib");
        //獲取加載類的實(shí)例
        Object object=myClass.newInstance();
        //獲取該類一個(gè)名為fib,且參數(shù)為int的方法
        Method method=myClass.getMethod("fib",int.class);
        //執(zhí)行這個(gè)方法
        int result=method.invoke(object,4);
        //打印結(jié)果
        System.out.print(result);
        
        //output
        /**
         * 3
         * Process finished with exit code 0
         */
    }
}

執(zhí)行成功

我們來分析下,Fib類的加載過程,初始化自定義類加載器后,loadClass方法肯定將其委派到雙親Application ClassLoader,而Application ClassLoader又將其委派到Extension ClassLoader,繼而委派到Bootstrap ClassLoader.但是Bootstrap ClassLoader發(fā)現(xiàn)Fib并不在自己的加載能力范圍內(nèi),于是移向Extension ClassLoader,同理Extension ClassLoader只能加載/ext中的class,繼而讓給Application ClassLoader,而Application ClassLoader只加載classpath中的類,于是又回到我們自定義的MyClassLoader,幸好我們重寫了findClass方法進(jìn)而執(zhí)行了加載,否在findClass拋出找不到類的異常.至此Fib類加載完成.

結(jié)語

如上便是筆者對(duì)雙親委派模型的總結(jié),如有錯(cuò)誤,歡迎指正.

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/73936.html

相關(guān)文章

  • 深入理解虛擬機(jī)虛擬機(jī)加載機(jī)制

    摘要:最終形成可以被虛擬機(jī)最直接使用的類型的過程就是虛擬機(jī)的類加載機(jī)制。即重寫一個(gè)類加載器的方法驗(yàn)證驗(yàn)證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。 《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐(第二版》讀書筆記與常見相關(guān)面試題總結(jié) 本節(jié)常見面試題(推薦帶著問題閱讀,問題答案在文中都有提到): 簡單說說類加載過...

    MadPecker 評(píng)論0 收藏0
  • 虛擬機(jī)加載機(jī)制

    摘要:虛擬機(jī)為了保證一個(gè)類的方法在多線程環(huán)境中被正確地加鎖同步。但啟動(dòng)類加載器不可能認(rèn)識(shí)這些代碼。實(shí)現(xiàn)模塊化熱部署的關(guān)鍵則是它的自定義類加載器機(jī)制的實(shí)現(xiàn)。 概念區(qū)分:加載、類加載、類加載器 類加載是一個(gè)過程。 加載(Loading)是類加載這一個(gè)過程的階段。 類加載器是ClassLoader類或其子類。 本文中的類的描述都包括了類和接口的可能性,因?yàn)槊總€(gè)Class文件都有可能代表J...

    airborne007 評(píng)論0 收藏0
  • Java加載機(jī)制

    摘要:如果需要支持類的動(dòng)態(tài)加載或需要對(duì)編譯后的字節(jié)碼文件進(jìn)行解密操作等,就需要與類加載器打交道了。雙親委派模型,雙親委派模型,約定類加載器的加載機(jī)制。任何之類的字節(jié)碼都無法調(diào)用方法,因?yàn)樵摲椒ㄖ荒茉陬惣虞d的過程中由調(diào)用。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級(jí)算法 GC策略的評(píng)價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card table數(shù)據(jù)...

    aervon 評(píng)論0 收藏0
  • 加載機(jī)制,雙親委派模型,搞定大廠高頻面試題

    摘要:驗(yàn)證驗(yàn)證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會(huì)危害虛擬機(jī)自身的安全。字節(jié)碼驗(yàn)證通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的符合邏輯的。 看過這篇文章,大廠面試你「雙親委派模型」,硬氣的說一句,你怕啥? 讀該文章姿勢(shì) 打開手頭的 IDE,按照文章內(nèi)容及思路進(jìn)行代碼跟蹤與思考 手頭沒有 IDE,先收藏,回頭看 (萬一哪次面試問...

    Object 評(píng)論0 收藏0
  • JVM加載過程 & 雙親委派模型

    摘要:類加載過程雙親委派模型聲明文章均為本人技術(shù)筆記,轉(zhuǎn)載請(qǐng)注明出處類加載過程類加載機(jī)制將類描述數(shù)據(jù)從文件中加載到內(nèi)存,并對(duì)數(shù)據(jù)進(jìn)行,解析和初始化,最終形成被直接使用的類型。深入理解虛擬機(jī)高級(jí)特性與最佳實(shí)踐加載加載階段由類加載器負(fù)責(zé),過程見類加載 JVM類加載過程 & 雙親委派模型 聲明 文章均為本人技術(shù)筆記,轉(zhuǎn)載請(qǐng)注明出處https://segmentfault.com/u/yzwall ...

    happen 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<