1、用戶自定義的類加載器:
要創建用戶自己的類加載器,只需要擴展java.lang.ClassLoader類,然后覆蓋它的findClass(String name)方法即可,該方法根據參數指定類的名字,返回對應的Class對象的引用。
findClass protected Class<?> findClass(String name) throws ClassNotFoundException
使用指定的二進制名稱查找類。此方法應該被類加載器的實現重寫,該實現按照委托模型來加載類。在通過父類加載器檢查所請求的類后,此方法將被 loadClass 方法調用。默認實現拋出一個 ClassNotFoundException。
參數: name - 類的二進制名稱
返回: 得到的 Class 對象
拋出: ClassNotFoundException - 如果無法找到類
從以下版本開始: 1.2
public class MyClassLoader extends ClassLoader { //類加載器名稱 private String name; //加載類的路徑 private String path = "D:/"; private final String fileType = ".class"; public MyClassLoader(String name){ //讓系統類加載器成為該 類加載器的父加載器 super(); this.name = name; } public MyClassLoader(ClassLoader parent, String name){ //顯示指定該類加載器的父加載器 super(parent); this.name = name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } @Override public String toString() { return this.name; } /** * 獲取.class文件的字節數組 * @param name * @return */ private byte[] loaderClassData(String name){ InputStream is = null; byte[] data = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); this.name = this.name.replace(".", "/"); try { is = new FileInputStream(new File(path + name + fileType)); int c = 0; while(-1 != (c = is.read())){ baos.write(c); } data = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally{ try { is.close(); baos.close(); } catch (IOException e) { e.printStackTrace(); } } return data; } /** * 獲取Class對象 */ @Override public Class<?> findClass(String name){ byte[] data = loaderClassData(name); return this.defineClass(name, data, 0, data.length); } public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { //loader1的父加載器為系統類加載器 MyClassLoader loader1 = new MyClassLoader("loader1"); loader1.setPath("D:/lib1/"); //loader2的父加載器為loader1 MyClassLoader loader2 = new MyClassLoader(loader1, "loader2"); loader2.setPath("D:/lib2/"); //loader3的父加載器為根類加載器 MyClassLoader loader3 = new MyClassLoader(null, "loader3"); loader3.setPath("D:/lib3/"); Class clazz = loader2.loadClass("Sample"); Object object = clazz.newInstance(); } }
public class Sample { public Sample(){ System.out.println("Sample is loaded by " + this.getClass().getClassLoader()); new A(); } }
public class A { public A(){ System.out.println("A is loaded by " + this.getClass().getClassLoader()); } }
當執行loader2.loaderClass("Sample")時,先由它上層的所有父加載器嘗試加載Sample類。loader1從D:/lib1/目錄下成功的加載了Sample類,因此laoder1是Sample類的定義類加載器,loader1和loader2是Sample類的初始類加載器。
當執行loader3.loadClass("Sample")時,先由它上層的所有父加載器嘗試加載Sample類。loader3的父加載器為根類加載器,它無法加載Sample類,接着loader3從D:/lib3/目錄下成功地加載了Sample類,因此loader3是Sample類的定義類加載器即初始類加載器。
在Sample類中主動使用了A類,當執行Sample類的構造方法中的new A()語句時,Java虛擬機需要先加載Dog類,Java虛擬機會勇Sample類的定義類加載器去加載Dog類,加載過程也同樣采用父親委托機制。
同一個命名空間內的類是相互可見的。
子加載器的命名空間包含所有父加載器的命名空間。因此子加載器加載的類能看見父加載器加載的類。例如系統類加載器加載的類能看見根類加載器加載的類。
由父加載器加載的類不能看見子加載器加載的類。
如果兩個加載器之間沒有直接或間接的父子關系,那么它們各自加載的類相互不可見。
當兩個不同命名空間內的類相互不可見時,可以采用Java的反射機制來訪問實例的屬性和方法。
轉載自:http://www.itzhai.com/java-virtual-machine-notes-custom-class-loader-implementation-and-use-of.html