如java.net.URLClassLoader$3$1 表示URLClassLoader的第三個(gè)匿名內(nèi)部類中的第一個(gè)匿名內(nèi)部類。
示例:
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()); }}
打印:
/*null 根類加載器----------------sun.misc.Launcher$AppClassLoader@18b4aac2----------------null 為空 */
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)是:
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í)行。
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é)果:
//只輸出了com.example.demo.com.jvm.Test1@1eb44e46
基于上例重構(gòu) 新增自定義路徑將class字節(jié)碼路徑放在其他位置 此時(shí)父類加載器appClassLoader無法加載 此時(shí)就會(huì)調(diào)用自己的findClass() 需要將classpath 下的需要加載的.class刪除。
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方法。
調(diào)用findClass
方法只是拋出了一個(gè)異常所有我們?cè)谧远x類加載器時(shí)必須重寫對(duì)應(yīng)方法。
重寫方法
當(dāng)我們調(diào)用對(duì)應(yīng)的方法完畢。
調(diào)用完畢
重寫loadClassData方法將獲取對(duì)應(yīng)二進(jìn)制類名文件字節(jié)數(shù)組。
重寫loadClassData
在通過方法獲取對(duì)應(yīng)二進(jìn)制名稱的Class對(duì)象。
通過defineClass
而在ClassLoader中的defineClass方法調(diào)用了重載的defineClass方法多加了個(gè)ProtectionDomainProtectionDomain 類封裝域的特征,域中包裝一個(gè)類集合,在代表給定的主體集合執(zhí)行這些類的實(shí)例時(shí)會(huì)授予它們一個(gè)權(quán)限集合。主要是支持支持動(dòng)態(tài)安全策略。
在這個(gè)方法里面才是真正獲取對(duì)應(yīng)二進(jìn)制名字的Class對(duì)象。
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ì)象。
ClassLoader 中l(wèi)oadClass 此時(shí)獲取的Class還沒有鏈接 只是剛加載到JVM中。
如果類被發(fā)現(xiàn)使用上述步驟,和解析標(biāo)志為真,此方法將調(diào)用{@link#resolveClass(Class)}方法的結(jié)果類對(duì)象。
子類ClassLoader被鼓勵(lì)重寫{@link#findClass(String)},而不是這個(gè)方法。
在整個(gè)類裝入過程中除非被覆蓋,否則此方法對(duì)的結(jié)果進(jìn)行同步{@link #getClassLoadingLock getClassLoadingLock}方法。
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)。
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è)完全相同的類,父加載器加載的類不可以看到子類加載器加載的類,但是子類加載器加載的類可以看到父類加載器加載的類。
解釋:
命名空間
上例繼續(xù)改造://將loader1作為loader2的父類加載器。
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。
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); }}
命名空間一致。
命名空間一致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