日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

JVM類加載:如何手寫自定義類加載器,命名空間詳解

來源: 責(zé)編: 時(shí)間:2024-04-09 09:06:37 193觀看
導(dǎo)讀二進(jìn)制名字如java.net.URLClassLoader$3$1 表示URLClassLoader的第三個(gè)匿名內(nèi)部類中的第一個(gè)匿名內(nèi)部類。ClassLoader分析A class loader is an object that is responsible for loading classes. The class ClassLoa

VMo28資訊網(wǎng)——每日最新資訊28at.com

二進(jìn)制名字

VMo28資訊網(wǎng)——每日最新資訊28at.com

如java.net.URLClassLoader$3$1 表示URLClassLoader的第三個(gè)匿名內(nèi)部類中的第一個(gè)匿名內(nèi)部類。VMo28資訊網(wǎng)——每日最新資訊28at.com

ClassLoader分析A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a “class file” of that name from a file system. Every Class object contains a reference to the ClassLoader that defined it. Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader.
  • 類加載器是負(fù)責(zé)加載類的對(duì)象。類加載器是一個(gè)抽象類。給定類的二進(jìn)制名,類加載器應(yīng)該嘗試定位或生成構(gòu)成類定義的數(shù)據(jù)(回去查找對(duì)應(yīng)的class文件如果沒有解析成class文件)。一個(gè)典型的策略是將名稱轉(zhuǎn)換為文件名,然后從文件中讀取該名稱的“類文件”系統(tǒng)。(我們編寫的java程序類都是這樣運(yùn)行)。
  • 每個(gè)類對(duì)象都包含對(duì)定義它的類加載器的引用(getClassLoader()獲取當(dāng)前類的類加載器)。
  • 數(shù)組類的類對(duì)象不是由類加載器創(chuàng)建的,而是由類加載器創(chuàng)建的根據(jù)Java運(yùn)行時(shí)的要求自動(dòng)執(zhí)行(數(shù)組類對(duì)象是由jvm虛擬機(jī)動(dòng)態(tài)創(chuàng)建的)。數(shù)組類的類加載器,如 getclassloader()返回的類與它的元素類型的類裝入器相同(數(shù)組元素類型是什么類加載器就是什么類型);如果 元素類型是基本(原生8種)類型,因此數(shù)組類沒有類裝入器。
  • 應(yīng)用程序?qū)崿F(xiàn)的ClassLoader類加載器為了擴(kuò)展Java虛擬機(jī)動(dòng)態(tài)加載的方式類。

示例:VMo28資訊網(wǎng)——每日最新資訊28at.com

public class Test15 {    public static void main(String[] args) {        String[] strings = new String[2];        System.out.println(strings.getClass().getClassLoader()); //string[]數(shù)組元素類型是String 在rt.jar包中是由根類加載器加載的        System.out.println("----------------");        Test15[] test15s = new Test15[2];        System.out.println(test15s.getClass().getClassLoader());//同理 該元素是由AppClassLoader系統(tǒng)類加載器加載的 但是數(shù)組本身不是由類加載器加載        System.out.println("----------------");        int[] ints = new int[2];//如果 元素類型是基本(原生8種)類型,因此數(shù)組類沒有類裝入器。        System.out.println(ints.getClass().getClassLoader());            }}

打印:VMo28資訊網(wǎng)——每日最新資訊28at.com

/*null 根類加載器----------------sun.misc.Launcher$AppClassLoader@18b4aac2----------------null 為空 */
  • 安全管理器通常會(huì)使用類裝入器來指示安全域(類加載始終伴隨著安全管理器所以類加載是安全的)
  • ClassLoader類使用委托模型進(jìn)行搜索類和資源。ClassLoader的每個(gè)實(shí)例都有一個(gè)關(guān)聯(lián)的父類裝入器。當(dāng)請(qǐng)求查找一個(gè)類或資源,一個(gè)類加載器實(shí)例將委托父類搜索類或資源,然后再嘗試查找類或資源本身。虛擬機(jī)的內(nèi)置類加載器,稱為“啟動(dòng)/根類加載器”,本身沒有父類,但可以充當(dāng)類裝入器實(shí)例的父類。
  • 支持類的并發(fā)加載的類加載器稱為 并行能力類加載器,需要注冊(cè)類的初始化時(shí)間registerAsParallelCapable。ClassLoader.registerAsParallelCapable這個(gè)方法。注意,類裝入器類被注冊(cè)為并行類默認(rèn)為able。但是,它的子類仍然需要注冊(cè)它們自己如果他們是并行的能力。
  • 委托模型不嚴(yán)格的環(huán)境層次結(jié)構(gòu),類加載器需要能夠并行,否則類加載可能導(dǎo)致死鎖,因?yàn)榧虞d器鎖被持有類加載過程的持續(xù)時(shí)間(參見{@link #loadClass)方法。
  • 通常,Java虛擬機(jī)從本地文件加載類平臺(tái)相關(guān)的系統(tǒng)。例如,在UNIX系統(tǒng)中在CLASSPATH環(huán)境變量定義的目錄加載類
  • 然而,有些類可能不是起源于一個(gè)文件;他們可能會(huì)產(chǎn)生從其他來源,如網(wǎng)絡(luò),或它們可以由一個(gè)應(yīng)用程序(動(dòng)態(tài)代理)。方法{@link #defineClass(String, byte[], int, int)defineClass}將字節(jié)數(shù)組轉(zhuǎn)換為類的實(shí)例可以使用以下命令創(chuàng)建這個(gè)新定義的類的實(shí)例 {@link Class#newInstance Class.newInstance}。
  • 類加載器創(chuàng)建的對(duì)象的方法和構(gòu)造函數(shù)可以引用其他類。要確定所引用的類即Java虛擬機(jī)調(diào)用{@link #loadClass loadClass}方法(這個(gè)方法解決這個(gè)問題)最初創(chuàng)建類的類加載器。
ClassLoader loade = new NetworkClassLoader(host,port);Object main = loader.loadClass("Main", true).newInstance();

自定義加載器子類必須定義兩個(gè)方法{@link#findClass findClass}和loadClassData加載類來自網(wǎng)絡(luò)。一旦它下載了構(gòu)成類的字節(jié),應(yīng)該使用方法{@link #defineClass defineClass} to創(chuàng)建一個(gè)類實(shí)例。一個(gè)示例實(shí)現(xiàn)是:VMo28資訊網(wǎng)——每日最新資訊28at.com

class NetworkClassLoader extends ClassLoader {          String host;          int port;           public Class findClass(String name) {              byte[] b = loadClassData(name);              return defineClass(name, b, 0, b.length);//通過名字將Class對(duì)象返回給調(diào)用者          }           private byte[] loadClassData(String name) {              // load the class data from the connection             .          }      }

編寫自定義類加載器

自定一 此時(shí)因?yàn)樵贑lassPath下 所以會(huì)調(diào)用父類AppClassLoader的系統(tǒng)類加載器 所以自定義的的findClass不會(huì)被執(zhí)行。VMo28資訊網(wǎng)——每日最新資訊28at.com

public class Test16 extends ClassLoader {    private String classLoaderName;    private final String fileExtension = ".class";    public Test16(String classLoaderName) {        // this(checkCreateClassLoader(), getSystemClassLoader());        // ClassLoader中當(dāng)創(chuàng)建新的類加載器返回的的是系統(tǒng)類加載器, 所以當(dāng)創(chuàng)建新的類加載器 默認(rèn)父加載器為系統(tǒng)類加載器        super();//可加可不加        this.classLoaderName = classLoaderName;    }    public Test16(ClassLoader parent, String classLoaderName) {        // this(checkCreateClassLoader(), parent);        //ClassLoader中當(dāng)創(chuàng)建新的類加載器自定義父加載器 如 :        //a繼承b b繼承ClassLoader  此時(shí)a可以拿這個(gè)構(gòu)造方法將b作為自己的雙親 不一定都交給系統(tǒng)類加載器        super(parent);        this.classLoaderName = classLoaderName;    }    /**     * 查找指定二進(jìn)制名字的class 這個(gè)方法應(yīng)該被子類加載器實(shí)現(xiàn)重寫,再檢查完對(duì)應(yīng)父加載器之后該方法會(huì)被loaderClass()方法調(diào)用 ,     * 在父類中  throw new ClassNotFoundException(name); 只是拋出來一個(gè)異常必須重寫     * 如:     * java.lang.String     *     * @param className     * @return     * @throws ClassNotFoundException     */    @Override    protected Class<?> findClass(String className) throws ClassNotFoundException {        //對(duì)應(yīng)二進(jìn)制名字對(duì)應(yīng)的字節(jié)數(shù)組        byte[] data = this.loadClassData(className);                System.out.println("findClass invoked" + className);        System.out.println("class loader name" + classLoaderName);                //defineClass(類名,字節(jié)數(shù)據(jù),起,末) 創(chuàng)建類實(shí)例        return this.defineClass(className, data, 0, data.length);    }    //獲取文件字節(jié)數(shù)據(jù)    private byte[] loadClassData(String name) {        InputStream is = null;        byte[] data = null;        ByteArrayOutputStream baos = null;        try {            //傳過來的文件名加上后綴            is = new FileInputStream(new File(name + this.fileExtension));            baos = new ByteArrayOutputStream();            int ch = 0;            while (-1 != (ch = is.read())) {                baos.write(ch);            }            data = baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                is.close();                baos.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return data;    }    public static void main(String[] args) throws Exception {        Test16 test16 = new Test16("test16");        test(test16);    }    public static void test(ClassLoader classLoader) throws IllegalAccessException, Exception {        //改方法會(huì)調(diào)用我們重寫之后的findClass方法        Class<?> clasz = classLoader.loadClass("com.example.demo.com.jvm.Test1");        Object o = clasz.newInstance();        System.out.println(o);    }}

打印結(jié)果:VMo28資訊網(wǎng)——每日最新資訊28at.com

//只輸出了com.example.demo.com.jvm.Test1@1eb44e46

基于上例重構(gòu) 新增自定義路徑將class字節(jié)碼路徑放在其他位置 此時(shí)父類加載器appClassLoader無法加載 此時(shí)就會(huì)調(diào)用自己的findClass() 需要將classpath 下的需要加載的.class刪除。VMo28資訊網(wǎng)——每日最新資訊28at.com

public class Test16 extends ClassLoader {    private String classLoaderName;    //路徑    private String path;    private final String fileExtension = ".class";    public Test16(String classLoaderName) {        // this(checkCreateClassLoader(), getSystemClassLoader());        // ClassLoader中當(dāng)創(chuàng)建新的類加載器返回的的是系統(tǒng)類加載器, 所以當(dāng)創(chuàng)建新的類加載器 默認(rèn)父加載器為系統(tǒng)類加載器        super();//可加可不加        this.classLoaderName = classLoaderName;    }    public void setPath(String path) {        this.path = path;    }    public Test16(ClassLoader parent, String classLoaderName) {        // this(checkCreateClassLoader(), parent);        //ClassLoader中當(dāng)創(chuàng)建新的類加載器自定義父加載器 如 :        //a繼承b b繼承ClassLoader  此時(shí)a可以拿這個(gè)構(gòu)造方法將b作為自己的雙親 不一定都交給系統(tǒng)類加載器        super(parent);        this.classLoaderName = classLoaderName;    }    /**     * 查找指定二進(jìn)制名字的class 這個(gè)方法應(yīng)該被子類加載器實(shí)現(xiàn)重新,再檢查完對(duì)應(yīng)父加載器之后該方法會(huì)被loaderClass()方法調(diào)用 ,     * 在父類中  throw new ClassNotFoundException(name); 只是拋出來一個(gè)異常必須重寫     * 如:     * java.lang.String     *     * @param className     * @return     * @throws ClassNotFoundException     */    @Override    protected Class<?> findClass(String className) throws ClassNotFoundException {        //對(duì)應(yīng)二進(jìn)制名字對(duì)應(yīng)的字節(jié)數(shù)組        byte[] data = this.loadClassData(className);        System.out.println("findClass invoked" + className);        System.out.println("class loader name= " + classLoaderName);        //defineClass(類名,字節(jié)數(shù)據(jù),起,末) 創(chuàng)建類實(shí)例        return this.defineClass(className, data, 0, data.length);    }    //獲取文件字節(jié)數(shù)據(jù)    private byte[] loadClassData(String className) {        InputStream is = null;        byte[] data = null;        ByteArrayOutputStream baos = null;        className = className.replace(".", "http://");        try {            //傳過來的文件名加上后綴            is = new FileInputStream(new File(this.path + className + this.fileExtension));            baos = new ByteArrayOutputStream();            int ch = 0;            while (-1 != (ch = is.read())) {                baos.write(ch);            }            data = baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                is.close();                baos.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return data;    }    public static void main(String[] args) throws Exception {        Test16 test16 = new Test16("test16");//        test16.setPath("D://workspaces//zookeeper//target//classes//");        test16.setPath("E://cx//");        //改方法會(huì)調(diào)用我們重寫之后的findClass方法        Class<?> clasz = test16.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz.hashCode());        Object o = clasz.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o);    }}
此時(shí)findClass中的打印語句執(zhí)行了 findClass invokedcom.example.demo.com.jvm.Test1class loader name= test16class: 1365202186com.example.demo.com.jvm.Test1@626b2d4a

當(dāng)我們?cè)诰帉懲曜远x類加載器時(shí)重寫了loadClassData和findClass方法。在main方法中實(shí)例化Test16對(duì)象調(diào)用返回系統(tǒng)類加載器的構(gòu)造函數(shù),因?yàn)樵赾lasspath路徑以上(雙親委托下并沒有找到對(duì)應(yīng)的.class文件 所以自定義加載器去加載 此時(shí)調(diào)用classLoader的loadClass方法獲取對(duì)應(yīng)的Class實(shí)例 此時(shí)自定義類加載器并沒有直接調(diào)用findClass方法 而是在loadClass方法中ClassLoader幫我們直接調(diào)用了我們自己重寫好的findclass方法。VMo28資訊網(wǎng)——每日最新資訊28at.com

VMo28資訊網(wǎng)——每日最新資訊28at.com

調(diào)用findClassVMo28資訊網(wǎng)——每日最新資訊28at.com

方法只是拋出了一個(gè)異常所有我們?cè)谧远x類加載器時(shí)必須重寫對(duì)應(yīng)方法。VMo28資訊網(wǎng)——每日最新資訊28at.com

VMo28資訊網(wǎng)——每日最新資訊28at.com

重寫方法VMo28資訊網(wǎng)——每日最新資訊28at.com

當(dāng)我們調(diào)用對(duì)應(yīng)的方法完畢。VMo28資訊網(wǎng)——每日最新資訊28at.com

VMo28資訊網(wǎng)——每日最新資訊28at.com

調(diào)用完畢VMo28資訊網(wǎng)——每日最新資訊28at.com

重寫loadClassData方法將獲取對(duì)應(yīng)二進(jìn)制類名文件字節(jié)數(shù)組。VMo28資訊網(wǎng)——每日最新資訊28at.com

VMo28資訊網(wǎng)——每日最新資訊28at.com

重寫loadClassDataVMo28資訊網(wǎng)——每日最新資訊28at.com

在通過方法獲取對(duì)應(yīng)二進(jìn)制名稱的Class對(duì)象。VMo28資訊網(wǎng)——每日最新資訊28at.com

VMo28資訊網(wǎng)——每日最新資訊28at.com

通過defineClassVMo28資訊網(wǎng)——每日最新資訊28at.com

而在ClassLoader中的defineClass方法調(diào)用了重載的defineClass方法多加了個(gè)ProtectionDomainProtectionDomain 類封裝域的特征,域中包裝一個(gè)類集合,在代表給定的主體集合執(zhí)行這些類的實(shí)例時(shí)會(huì)授予它們一個(gè)權(quán)限集合。主要是支持支持動(dòng)態(tài)安全策略。VMo28資訊網(wǎng)——每日最新資訊28at.com

在這個(gè)方法里面才是真正獲取對(duì)應(yīng)二進(jìn)制名字的Class對(duì)象。VMo28資訊網(wǎng)——每日最新資訊28at.com

protected final Class<?> defineClass(String name, byte[] b, int off, int len,                                         ProtectionDomain protectionDomain)        throws ClassFormatError    {        //前置處理        protectionDomain = preDefineClass(name, protectionDomain);        String source = defineClassSourceLocation(protectionDomain);        //此時(shí)調(diào)用底層本地C++代碼獲取Class         Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);        //后置處理拼接對(duì)象后綴名        postDefineClass(c, protectionDomain);        return c;    }

自此程序運(yùn)行結(jié)束 返回Class對(duì)象。VMo28資訊網(wǎng)——每日最新資訊28at.com

ClassLoader 中l(wèi)oadClass 詳解

  • classLoader.lordClass和forName的區(qū)別(主動(dòng)加載和被動(dòng)加載的區(qū)別)。
  • class.forName()除了將類的.class文件加載到j(luò)vm中之外,還會(huì)對(duì)類進(jìn)行解釋,執(zhí)行類中的static塊。
  • 而classLoader.lordClass只干一件事情,就是將.class文件加載到j(luò)vm中,不會(huì)執(zhí)行static中的內(nèi)容,只有在newInstance才會(huì)去執(zhí)行static塊。(不初始)。
  • Class.forName(name, initialize, loader)帶參函數(shù)也可控制是否加載static塊。并且只有調(diào)用了newInstance()方法才用調(diào)用構(gòu)造函數(shù),來創(chuàng)建類的對(duì)象(初始)。

ClassLoader 中l(wèi)oadClass 此時(shí)獲取的Class還沒有鏈接 只是剛加載到JVM中。VMo28資訊網(wǎng)——每日最新資訊28at.com

加載指定的二進(jìn)制名的類此方法的實(shí)現(xiàn)會(huì)默認(rèn)按照以下的順序?qū)ふ翌?/h3>
  • 調(diào)用{@link #findLoadedClass(String)}檢查類是否已經(jīng)加載(一個(gè)類只能被加載一次)。
  • 調(diào)用父類的{@link #loadClass(String) loadClass}方法,如果父類是null 就會(huì)使用虛擬機(jī)內(nèi)置的根類加載器。
  • 調(diào)用{@link #findClass(String)}方法查找。

如果類被發(fā)現(xiàn)使用上述步驟,和解析標(biāo)志為真,此方法將調(diào)用{@link#resolveClass(Class)}方法的結(jié)果類對(duì)象。
子類ClassLoader被鼓勵(lì)重寫{@link#findClass(String)},而不是這個(gè)方法。
VMo28資訊網(wǎng)——每日最新資訊28at.com

在整個(gè)類裝入過程中除非被覆蓋,否則此方法對(duì)的結(jié)果進(jìn)行同步{@link #getClassLoadingLock getClassLoadingLock}方法。VMo28資訊網(wǎng)——每日最新資訊28at.com

protected Class<?> loadClass(String name, boolean resolve)        throws ClassNotFoundException    {        synchronized (getClassLoadingLock(name)) {            // 檢查類是否已經(jīng)加載(一個(gè)類只能被加載一次)            Class<?> c = findLoadedClass(name);            if (c == null) {                long t0 = System.nanoTime();                try {                    if (parent != null) {                       //如果父類不是null 就會(huì)使用虛擬機(jī)內(nèi)置的根類加載器去加載二進(jìn)制名(name對(duì)應(yīng)的數(shù)據(jù)),                       //子類ClassLoader被鼓勵(lì)重寫                        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();                }            }           // 如果類被發(fā)現(xiàn)使用上述步驟,和解析標(biāo)志為真,此方法將調(diào)用{@link#resolveClass(Class)}方法的結(jié)果類對(duì)象。            if (resolve) {                resolveClass(c);            }            //返回Class            return c;        }    }

基于上例Test16繼續(xù)重構(gòu)。VMo28資訊網(wǎng)——每日最新資訊28at.com

public class Test16 extends ClassLoader {    private String classLoaderName;    //路徑    private String path;    private final String fileExtension = ".class";    public Test16(String classLoaderName) {        // this(checkCreateClassLoader(), getSystemClassLoader());        // ClassLoader中當(dāng)創(chuàng)建新的類加載器返回的的是系統(tǒng)類加載器, 所以當(dāng)創(chuàng)建新的類加載器 默認(rèn)父加載器為系統(tǒng)類加載器        super();//可加可不加        this.classLoaderName = classLoaderName;    }    public void setPath(String path) {        this.path = path;    }    public Test16(ClassLoader parent, String classLoaderName) {        // this(checkCreateClassLoader(), parent);        //ClassLoader中當(dāng)創(chuàng)建新的類加載器自定義父加載器 如 :        //a繼承b b繼承ClassLoader  此時(shí)a可以拿這個(gè)構(gòu)造方法將b作為自己的雙親 不一定都交給系統(tǒng)類加載器        super(parent);        this.classLoaderName = classLoaderName;    }    /**     * 查找指定二進(jìn)制名字的class 這個(gè)方法應(yīng)該被子類加載器實(shí)現(xiàn)重新,再檢查完對(duì)應(yīng)父加載器之后該方法會(huì)被loaderClass()方法調(diào)用 ,     * 在父類中  throw new ClassNotFoundException(name); 只是拋出來一個(gè)異常必須重寫     * 如:     * java.lang.String     *     * @param className     * @return     * @throws ClassNotFoundException     */    @Override    protected Class<?> findClass(String className) throws ClassNotFoundException {        //對(duì)應(yīng)二進(jìn)制名字對(duì)應(yīng)的字節(jié)數(shù)組        byte[] data = this.loadClassData(className);        System.out.println("findClass invoked:" + className);        System.out.println("class loader name: " + classLoaderName);        //defineClass(類名,字節(jié)數(shù)據(jù),起,末) 創(chuàng)建類實(shí)例        return this.defineClass(className, data, 0, data.length);    }    //獲取文件字節(jié)數(shù)據(jù)    private byte[] loadClassData(String className) {        InputStream is = null;        byte[] data = null;        ByteArrayOutputStream baos = null;        className = className.replace(".", "http://");        try {            //傳過來的文件名加上后綴            is = new FileInputStream(new File(this.path + className + this.fileExtension));            baos = new ByteArrayOutputStream();            int ch = 0;            while (-1 != (ch = is.read())) {                baos.write(ch);            }            data = baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                is.close();                baos.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return data;    }    public static void main(String[] args) throws Exception {        Test16 test16 = new Test16("test16");//        test16.setPath("D://workspaces//zookeeper//target//classes//");        test16.setPath("E://cx//");        //改方法會(huì)調(diào)用我們重寫之后的findClass方法        Class<?> clasz = test16.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz.hashCode());        Object o = clasz.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o);        Test16 test162 = new Test16("test17");        Class<?> clasz2 = test16.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz2.hashCode());        Object o2 = clasz2.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o2);    }}
/*當(dāng)classPath下有對(duì)應(yīng)的加載的.class時(shí) 第二次交給父類加載器發(fā)現(xiàn)已經(jīng)加載所以字節(jié)拿過來用 所以此時(shí)獲取的Class類時(shí)一致的class: 515132998com.example.demo.com.jvm.Test1@6504e3b2class: 515132998com.example.demo.com.jvm.Test1@515f550a當(dāng)classPath下沒有對(duì)應(yīng)的加載的.class 制定了對(duì)應(yīng)的路徑 此時(shí)類獲取幾次就會(huì)加載幾次 涉及到了命名空間的問題findClass invoked:com.example.demo.com.jvm.Test1class loader name: test16class: 1365202186com.example.demo.com.jvm.Test1@626b2d4a--------------兩個(gè)不同的命名空間------------------findClass invoked:com.example.demo.com.jvm.Test1class loader name: test17class: 932583850com.example.demo.com.jvm.Test1@cac736f */

總結(jié):同一個(gè)命名空間不會(huì)出現(xiàn)兩個(gè)完全相同的類,不同的命名空間會(huì)出現(xiàn)兩個(gè)完全相同的類,父加載器加載的類不可以看到子類加載器加載的類,但是子類加載器加載的類可以看到父類加載器加載的類。VMo28資訊網(wǎng)——每日最新資訊28at.com

解釋:VMo28資訊網(wǎng)——每日最新資訊28at.com

VMo28資訊網(wǎng)——每日最新資訊28at.com

命名空間VMo28資訊網(wǎng)——每日最新資訊28at.com

上例繼續(xù)改造://將loader1作為loader2的父類加載器。VMo28資訊網(wǎng)——每日最新資訊28at.com

public class Test16 extends ClassLoader {    private String classLoaderName;    //路徑    private String path;    private final String fileExtension = ".class";    public Test16(String classLoaderName) {        // this(checkCreateClassLoader(), getSystemClassLoader());        // ClassLoader中當(dāng)創(chuàng)建新的類加載器返回的的是系統(tǒng)類加載器, 所以當(dāng)創(chuàng)建新的類加載器 默認(rèn)父加載器為系統(tǒng)類加載器        super();//可加可不加        this.classLoaderName = classLoaderName;    }    public void setPath(String path) {        this.path = path;    }    public Test16(ClassLoader parent, String classLoaderName) {        // this(checkCreateClassLoader(), parent);        //ClassLoader中當(dāng)創(chuàng)建新的類加載器自定義父加載器 如 :        //a繼承b b繼承ClassLoader  此時(shí)a可以拿這個(gè)構(gòu)造方法將b作為自己的雙親 不一定都交給系統(tǒng)類加載器        super(parent);        this.classLoaderName = classLoaderName;    }    /**     * 查找指定二進(jìn)制名字的class 這個(gè)方法應(yīng)該被子類加載器實(shí)現(xiàn)重新,再檢查完對(duì)應(yīng)父加載器之后該方法會(huì)被loaderClass()方法調(diào)用 ,     * 在父類中  throw new ClassNotFoundException(name); 只是拋出來一個(gè)異常必須重寫     * 如:     * java.lang.String     *     * @param className     * @return     * @throws ClassNotFoundException     */    @Override    protected Class<?> findClass(String className) throws ClassNotFoundException {        //對(duì)應(yīng)二進(jìn)制名字對(duì)應(yīng)的字節(jié)數(shù)組        byte[] data = this.loadClassData(className);        System.out.println("findClass invoked:" + className);        System.out.println("class loader name: " + classLoaderName);        //defineClass(類名,字節(jié)數(shù)據(jù),起,末) 創(chuàng)建類實(shí)例        return this.defineClass(className, data, 0, data.length);    }    //獲取文件字節(jié)數(shù)據(jù)    private byte[] loadClassData(String className) {        InputStream is = null;        byte[] data = null;        ByteArrayOutputStream baos = null;        className = className.replace(".", "http://");        try {            //傳過來的文件名加上后綴            is = new FileInputStream(new File(this.path + className + this.fileExtension));            baos = new ByteArrayOutputStream();            int ch = 0;            while (-1 != (ch = is.read())) {                baos.write(ch);            }            data = baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                is.close();                baos.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return data;    }    public static void main(String[] args) throws Exception {        Test16 loader1 = new Test16("loader1");//        test16.setPath("D://workspaces//zookeeper//target//classes//");        loader1.setPath("E://cx//");        //改方法會(huì)調(diào)用我們重寫之后的findClass方法        Class<?> clasz = loader1.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz.hashCode());        Object o = clasz.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o);//        System.out.println("------------兩個(gè)不同的命名空間--------------------");        Test16 loader2 = new Test16(loader1,"loader2");//將loader1作為loader2的父類加載器        loader2.setPath("E://cx//");        Class<?> clasz2 = loader2.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz2.hashCode());        Object o2 = clasz2.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o2);    }}
-------------------------------------------當(dāng)classPath下沒有對(duì)應(yīng)的加載的.class時(shí)Test16 loader2 = new Test16(loader1,"loader2");//將loader1作為loader2的父類加載器findClass invoked:com.example.demo.com.jvm.Test1class loader name: loader1class: 1365202186com.example.demo.com.jvm.Test1@626b2d4a  //此時(shí)父加載器loader1已經(jīng)加載完畢 loader2直接拿來使用class: 1365202186com.example.demo.com.jvm.Test1@5e91993f

通過上例繼續(xù)改造: 新增一個(gè)類加載器 父類設(shè)置為loader2。VMo28資訊網(wǎng)——每日最新資訊28at.com

public class Test16 extends ClassLoader {    private String classLoaderName;    //路徑    private String path;    private final String fileExtension = ".class";    public Test16(String classLoaderName) {        // this(checkCreateClassLoader(), getSystemClassLoader());        // ClassLoader中當(dāng)創(chuàng)建新的類加載器返回的的是系統(tǒng)類加載器, 所以當(dāng)創(chuàng)建新的類加載器 默認(rèn)父加載器為系統(tǒng)類加載器        super();//可加可不加        this.classLoaderName = classLoaderName;    }    public void setPath(String path) {        this.path = path;    }    public Test16(ClassLoader parent, String classLoaderName) {        // this(checkCreateClassLoader(), parent);        //ClassLoader中當(dāng)創(chuàng)建新的類加載器自定義父加載器 如 :        //a繼承b b繼承ClassLoader  此時(shí)a可以拿這個(gè)構(gòu)造方法將b作為自己的雙親 不一定都交給系統(tǒng)類加載器        super(parent);        this.classLoaderName = classLoaderName;    }    /**     * 查找指定二進(jìn)制名字的class 這個(gè)方法應(yīng)該被子類加載器實(shí)現(xiàn)重新,再檢查完對(duì)應(yīng)父加載器之后該方法會(huì)被loaderClass()方法調(diào)用 ,     * 在父類中  throw new ClassNotFoundException(name); 只是拋出來一個(gè)異常必須重寫     * 如:     * java.lang.String     *     * @param className     * @return     * @throws ClassNotFoundException     */    @Override    protected Class<?> findClass(String className) throws ClassNotFoundException {        //對(duì)應(yīng)二進(jìn)制名字對(duì)應(yīng)的字節(jié)數(shù)組        byte[] data = this.loadClassData(className);        System.out.println("findClass invoked:" + className);        System.out.println("class loader name: " + classLoaderName);        //defineClass(類名,字節(jié)數(shù)據(jù),起,末) 創(chuàng)建類實(shí)例        return this.defineClass(className, data, 0, data.length);    }    //獲取文件字節(jié)數(shù)據(jù)    private byte[] loadClassData(String className) {        InputStream is = null;        byte[] data = null;        ByteArrayOutputStream baos = null;        className = className.replace(".", "http://");        try {            //傳過來的文件名加上后綴            is = new FileInputStream(new File(this.path + className + this.fileExtension));            baos = new ByteArrayOutputStream();            int ch = 0;            while (-1 != (ch = is.read())) {                baos.write(ch);            }            data = baos.toByteArray();        } catch (Exception e) {            e.printStackTrace();        } finally {            try {                is.close();                baos.close();            } catch (IOException e) {                e.printStackTrace();            }        }        return data;    }    public static void main(String[] args) throws Exception {        Test16 loader1 = new Test16("loader1");//        test16.setPath("D://workspaces//zookeeper//target//classes//");        loader1.setPath("E://cx//");        //改方法會(huì)調(diào)用我們重寫之后的findClass方法        Class<?> clasz = loader1.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz.hashCode());        Object o = clasz.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o);        System.out.println();//        System.out.println("------------兩個(gè)不同的命名空間--------------------");        Test16 loader2 = new Test16(loader1, "loader2");//將loader1作為loader2的父類加載器        loader2.setPath("E://cx//");        Class<?> clasz2 = loader2.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz2.hashCode());        Object o2 = clasz2.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o2);        System.out.println();        Test16 loader3 = new Test16(loader2,"loader3");        loader3.setPath("E://cx//");        //改方法會(huì)調(diào)用我們重寫之后的findClass方法        Class<?> clasz3 = loader3.loadClass("com.example.demo.com.jvm.Test1");        System.out.println("class: " + clasz3.hashCode());        Object o3 = clasz3.newInstance();//對(duì)象內(nèi)存地址有哈希值        System.out.println(o3);    }}

命名空間一致。VMo28資訊網(wǎng)——每日最新資訊28at.com

命名空間一致findClass invoked:com.example.demo.com.jvm.Test1class loader name: loader1class: 1365202186com.example.demo.com.jvm.Test1@626b2d4a loader1 先去加類加載class: 1365202186com.example.demo.com.jvm.Test1@5e91993f loader2 交給父類父類交給appClassLoader加載發(fā)現(xiàn)已經(jīng)加載直接拿來用class: 1365202186com.example.demo.com.jvm.Test1@1c4af82c loader3 同上

本文鏈接:http://www.www897cc.com/showinfo-26-82180-0.htmlJVM類加載:如何手寫自定義類加載器,命名空間詳解

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 超級(jí)離譜的前端需求:搜索圖片里的文字

下一篇: 面試官:如何設(shè)計(jì)和實(shí)現(xiàn)一個(gè)帶過期時(shí)間的本地緩存?

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 商水县| 湄潭县| 涟水县| 民丰县| 漯河市| 垣曲县| 元氏县| 卢龙县| 泾阳县| 肇东市| 星座| 沙坪坝区| 舟山市| 淮滨县| 托里县| 宁河县| 卢湾区| 柘荣县| 桂东县| 荥阳市| 松潘县| 美姑县| 化州市| 天等县| 封开县| 顺昌县| 樟树市| 扎兰屯市| 鄂尔多斯市| 靖西县| 宁夏| 苗栗县| 砚山县| 大洼县| 合作市| 玉山县| 京山县| 新晃| 南城县| 南川市| 贵州省|