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

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

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

來源: 責(zé)編: 時(shí)間:2024-04-09 09:06:37 246觀看
導(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

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

二進(jìn)制名字

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

如java.net.URLClassLoader$3$1 表示URLClassLoader的第三個(gè)匿名內(nèi)部類中的第一個(gè)匿名內(nèi)部類。xgY28資訊網(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)加載的方式類。

示例:xgY28資訊網(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());            }}

打印:xgY28資訊網(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)是:xgY28資訊網(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í)行。xgY28資訊網(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é)果:xgY28資訊網(wǎng)——每日最新資訊28at.com

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

在整個(gè)類裝入過程中除非被覆蓋,否則此方法對(duì)的結(jié)果進(jìn)行同步{@link #getClassLoadingLock getClassLoadingLock}方法。xgY28資訊網(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)。xgY28資訊網(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è)完全相同的類,父加載器加載的類不可以看到子類加載器加載的類,但是子類加載器加載的類可以看到父類加載器加載的類。xgY28資訊網(wǎng)——每日最新資訊28at.com

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

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

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

上例繼續(xù)改造://將loader1作為loader2的父類加載器。xgY28資訊網(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。xgY28資訊網(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);    }}

命名空間一致。xgY28資訊網(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://m.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 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
久久精品91久久香蕉加勒比 | 欧美激情一区二区三区蜜桃视频 | 免费成人黄色av| 欧美成人综合一区| 欧美一区二区三区播放老司机| 久久久女女女女999久久| 久久蜜桃av一区精品变态类天堂| 亚洲一区二区黄色| 欧美性猛交一区二区三区精品| 韩国久久久久| 国产精品久久久久久久久久久久久久 | 亚洲伦理久久| 亚洲激情自拍| 亚洲综合精品一区二区| 久久精品亚洲| 欧美日本一区二区高清播放视频| 国产精品资源在线观看| 99视频+国产日韩欧美| 国产精品久久97| 亚洲视频精品| 欧美在线影院在线视频| 激情视频一区二区三区| 欧美视频一区二区在线观看 | 亚洲欧美日本另类| 宅男66日本亚洲欧美视频| 先锋a资源在线看亚洲| 国产欧美日韩激情| 亚洲人体偷拍| 欧美三级资源在线| 久久久www免费人成黑人精品| 国产精品成人观看视频国产奇米| 欧美在线网站| 亚洲第一精品福利| 欧美成人中文字幕| 国产精品久久久久77777| 久久夜色精品一区| 国语自产精品视频在线看一大j8| 午夜欧美精品| 国产精品视频免费观看www| 免费亚洲电影在线观看| 亚洲小视频在线| 亚洲午夜免费视频| 黄色亚洲在线| 国产综合色在线视频区| 国产精品高清免费在线观看| 欧美专区福利在线| 欧美三级中文字幕在线观看| 亚洲国产mv| 欧美在线不卡| 国产精品hd| 亚洲乱码久久| 欧美成年人在线观看| 国产日本精品| 亚洲资源av| 欧美日韩在线一区二区三区| 亚洲国产精品va在线看黑人动漫 | 亚洲一区久久久| 欧美区二区三区| 亚洲福利国产| 久久人人爽人人爽爽久久| 国产精品揄拍500视频| 亚洲天堂成人在线视频| 欧美日本一区二区视频在线观看| 伊人久久大香线蕉综合热线 | 麻豆精品视频在线观看| 国产综合色精品一区二区三区| 亚洲欧美激情在线视频| 欧美偷拍另类| 在线视频一区二区| 欧美日韩高清免费| 日韩特黄影片| 欧美国产成人在线| 亚洲韩国青草视频| 裸体一区二区三区| 亚洲大片免费看| 久久资源av| 亚洲电影免费在线观看| 另类人畜视频在线| 伊人久久噜噜噜躁狠狠躁 | 欧美国产高清| 亚洲人成免费| 欧美日本二区| 一区二区三区回区在观看免费视频| 欧美激情一区二区三区成人| 亚洲激情在线激情| 欧美精品九九99久久| 亚洲精品小视频| 欧美日韩国产成人在线| av成人黄色| 欧美亚州一区二区三区| 亚洲影院免费观看| 国产精品一区二区在线观看不卡 | 在线亚洲一区| 国产精品成人观看视频免费| 一区二区三区产品免费精品久久75| 欧美日韩精品不卡| 亚洲视频综合在线| 国产精品久久77777| 欧美一区二区三区在线| 国内精品久久久久影院薰衣草| 久久久久久午夜| 亚洲国产日韩在线| 欧美日韩国产成人在线观看| 国产精品99久久久久久有的能看| 国产精品久久久久久久久久久久久久 | 欧美日韩视频一区二区三区| 99riav久久精品riav| 欧美精选午夜久久久乱码6080| 99国产成+人+综合+亚洲欧美| 欧美日韩一区二区三区在线观看免| 亚洲无限av看| 国产亚洲精品福利| 麻豆精品精品国产自在97香蕉| 在线精品国精品国产尤物884a| 蜜桃精品久久久久久久免费影院| 亚洲精品一区二区网址 | 亚洲国产日韩欧美在线图片| 欧美日韩一二区| 欧美一级大片在线观看| 在线精品国产欧美| 欧美日韩国产色综合一二三四| 亚洲欧美日韩国产成人精品影院| 国产一区二区三区在线观看视频| 免费人成精品欧美精品| 一区二区久久久久久| 国产精品一区二区男女羞羞无遮挡 | 欧美伦理影院| 亚洲一区成人| 激情小说亚洲一区| 欧美久久影院| 欧美在线视频免费| 亚洲精品网站在线播放gif| 国产精品视频yy9099| 久久综合色影院| 亚洲免费大片| 国产色综合网| 欧美久久99| 久久精品成人一区二区三区| 亚洲人体影院| 国产亚洲精品一区二区| 欧美黄色大片网站| 欧美一级久久久久久久大片| 亚洲人成网站999久久久综合| 国产精品一区二区三区观看| 欧美电影在线观看完整版| 性做久久久久久久免费看| 亚洲精品久久在线| 国产日韩欧美综合一区| 欧美日韩国产三级| 久久久久久国产精品一区| 亚洲视频一二三| 亚洲国产欧洲综合997久久| 国产伦精品一区二区三区四区免费 | 一区二区欧美日韩视频| 狠狠色丁香婷婷综合| 欧美午夜免费| 欧美xxx在线观看| 欧美一区二区三区视频| 亚洲一区免费看| 欧美激情精品久久久久久蜜臀| 一区二区高清| 韩国av一区二区三区在线观看| 欧美日韩国产成人在线免费| 久久国产主播| 亚洲一二区在线| 亚洲经典视频在线观看| 国产亚洲精品aa| 欧美视频一区二区三区…| 麻豆精品视频在线| 欧美一区二区高清| 一本色道久久99精品综合| 亚洲第一在线| 国产亚洲欧美中文| 国产精品久久久久毛片软件 | 一区二区三区三区在线| 亚洲国产你懂的| 国内一区二区三区在线视频| 国产精品网曝门| 欧美日韩无遮挡| 欧美黄色免费| 老司机成人网| 久久精品成人| 久久xxxx| 欧美一区91| 午夜精彩视频在线观看不卡| 亚洲视频免费在线| 一区二区高清在线观看| 亚洲狼人精品一区二区三区| 亚洲国产精品电影| 在线播放日韩专区| 亚洲黄色av| 国产精品久久久亚洲一区| 女仆av观看一区| 久久人人爽人人爽爽久久| 久久av一区二区三区| 午夜精品区一区二区三| 亚洲综合日韩中文字幕v在线| 一本久久精品一区二区| 99在线精品视频在线观看| 99国产精品国产精品毛片| 亚洲精选在线| 日韩一区二区精品视频| 日韩一级大片在线| 日韩午夜视频在线观看|