百度了一下,通篇所有都是啓動類加載器,擴展類加載器,應用程序類加載器,還有就是雙親委託模式 。java
但是一圈下來,新手們依然不知道如何自定義一個類加載器,來生動的展示什麼是類加載器。app
首先咱們在E:upload下新建一個a/BB.java文件。編輯器
代碼以下:ide
package a; public class BB { private String a; public BB(){ } public BB(String a){ this.a=a; } public static void main(String[] args) { System.out.println("aaaaaaaaaa"); } }
編譯後出現BB.class字節碼文件ui
退回到上級目錄,由於包是到a目錄的。執行java a.BB;正確執行main方法this
如今咱們回到IDea編輯器中,將BB.class文件讀取到內存,而且利用反射進行實例化。idea
自定義類加載器 MyClassLoader.javaspa
package a; import java.io.*; import java.lang.reflect.Field; public class MyClassLoader extends ClassLoader{ @Override protected Class<?> findClass(String name) { byte[] bytes=null; //將點替換成斜槓 String fileName=name.replaceAll("\\.","/"); StringBuilder sb=new StringBuilder("E:"); sb.append(File.separator); sb.append("upload"); sb.append(File.separator); sb.append(fileName); sb.append(".class"); fileName=sb.toString(); try { InputStream is=new FileInputStream(fileName); ByteArrayOutputStream bos=new ByteArrayOutputStream(); byte[] buf=new byte[1024]; int r=0; while ((r=is.read(buf))!=-1){ bos.write(buf,0,r); } bytes=bos.toByteArray(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return defineClass(name,bytes,0,bytes.length); } public static void main(String[] args) throws Exception{ //自定義類加載器對象1 MyClassLoader c1=new MyClassLoader(); String className="a.BB";
//loadClass調用的就是findClass() Class clazz1=c1.loadClass(className); //自定義類加載器對象2 MyClassLoader c2=new MyClassLoader(); Class clazz2=c2.loadClass(className); System.out.println(clazz1.getClassLoader()); System.out.println(clazz2.getClassLoader()); if(clazz1!=clazz2){ System.out.println("不一樣的類加載器對象加載相同的class文件,會產生不一樣的類對象"); } Object obj1=clazz1.getDeclaredConstructor(new Class[]{String.class}).newInstance("自定義加載器加載進內存的"); Field fa=clazz1.getDeclaredField("a"); fa.setAccessible(true);//將私有變量設置成能夠訪問的權限 System.out.println(fa.get(obj1)); } }
執行結果:code
e.MyClassLoader@2b193f2d
e.MyClassLoader@4dc63996
不一樣的類加載器加載相同的class文件,會產生不一樣的類對象
自定義加載器加載進內存的
很明顯clazz1和clazz2是兩個類。對象
給BB.java中構造器傳入的字符串:「自定義加載器加載進內存的」 也在上面打印出來了。
注意:若是將a/BB.java文件拷貝到idea編輯器中。那麼MyClassLoader中的findClass就不會執行了。
由於MyClassLoader c1和MyClassLoader c2都繼承自ClassLoader,因此直接交給上級類加載器加載應用程序類加載器:Application ClassLoader;
應用程序類加載器會首先找到a/BB.class文件,並加入內存;此時就不會在繼續x向下傳播調用加載了。
類加載器在加載的時候虛擬機會首先調用加載器的私用方法loadClassInternal()
而這個方法惟一做用就是調用本身的loadClass()方法,若是loadClass()加載失敗了,則會調用本身的findClass()。
loadClass()也能被重寫,可是咱們不會這樣作,由於這樣作的話,全部的類都會走這個方法來加載類;那麼虛擬機內置的一些類也會用這個方法裏面的邏輯來加載,固定會報錯。