一個類加載器是一個負責加載類的對象,給定一個類的二進制名稱,類加載器嘗試查找或生成組成該類定義的數據信息。典型的是將這個名稱轉換成文件名稱而後從文件系統中讀取類文件
每個類對象包含一個定義它的類加載器。數組類的類對象不是經過類加載器建立;由java runtime時的須要自動建立。對於一個數組類的類加載器,返回與其元素類的加載器相同;若元素類型爲基本類型,那麼數組類沒有類加載器
應用程序實現子類化的類加載器爲了擴展jvm動態加載類的方法。類加載器一般經過安全管理表示安全域的方式被使用。
類加載器的類使用一個代理模型搜索類和資源,每個類加載器的實例都有一個關聯的父類加載器,當須要查找一個類or資源,一個類加載器實例將代理其父類加載器在嘗試查找到該類or資源以前。JVM內置加載器「bootstrap class loader」,一般做爲其餘類加載器的父類加載器。
並行的類加載器支持併發加載類而且要求它們的類在初始化的時調用registerAsParallelCapable進行登記。注意,默認經過登記並行的類加載器,它的子類如須要是並行的時,仍是須要進行登記。
在環境中的代理模型是不嚴格分層的。類加載器須要並行能力,不然可能致使死鎖,由於類加載器在類加載過程時持有鎖。
一般狀況下,JVM從一個平臺依賴性的本地文件系統加載類。eg在UNIX系統中,JVM從經過環境變量CLASSPATH定義的目錄加載類,然而有些類不是來源一個文件(eg:網絡or經過應用程序構建的)。defineClass方法將字節數組轉換爲類對象的實例,這個新定義的類就能夠建立使用newInstance。對象的構造器與行爲經過一個類加載器可能引用其餘類來建立,肯定類涉及到,JVM調用原來建立該類的類加載器的方法loadClass。eg:一個應用建立一個網絡類加載器處理從服務器上下載的類文件
ClassLoader loader = new NetWorkClassLoader(host, port);
Object main = loader.loadClass(「Main」, true).newInstance();
網絡類加載器子類必須定義findClass、loadClassData方法從網絡加載一個類。一旦下載組成該類的字節,應該使用defineClass方法建立一個類對象的實例
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
}
在類加載器的方法中,任何類名被設置爲類的二進制名稱字符串的參數,eg:有效的類名
java.lang.String
javax.swing.JSpinner$DefaultEditor
java.security.KeyStore$Builder$FileBuilder$1
java.net.URLClassLoader$3$1
包裝訪問多個類加載器使其做爲一個類加載器訪問
因爲類加載器實現方式不一樣,咱們可能須要向不一樣的類加載器查找某一個類or資源,因此提供一個包裝器實現java
public class ClassLoaderWrapper { ClassLoader defaultClassLoader; ClassLoader systemClassLoader;//typically the class loader used to start the application ClassLoaderWrapper() { try { systemClassLoader = ClassLoader.getSystemClassLoader(); } catch (SecurityException ignored) { } } //get a resource as a url using the current class path public URL getResourceAsURL(String resource) { return getResourceAsURL(resource, getClassLoaders(null)); } public URL getResourceAsURL(String resource, ClassLoader cl) { return getResourceAsURL(resource, getClassLoaders(cl)); } URL getResourceAsURL(String resource, ClassLoader[] cls) { URL url; for(ClassLoader cl: cls) { if(cl != null) { url = cl.getResource(resource); if(url == null) url = cl.getResource("/" + resource); if(url != null) return url; } } return null; } //get a resource as a input stream using the current class path public InputStream getResourceAsStream(String resource) { return getResourceAsStream(resource, getClassLoaders(null)); } public InputStream getResourceAsStream(String resource, ClassLoader cl) { return getResourceAsStream(resource, getClassLoaders(cl)); } InputStream getResourceAsStream(String resource, ClassLoader[] cls) { for(ClassLoader cl: cls) { if(cl != null) { InputStream in = cl.getResourceAsStream(resource); if(in == null) in = cl.getResourceAsStream("/" + resource); if(in != null) return in; } } return null; } //find a class on the classpath public Class<?> classForName(String name) throws ClassNotFoundException { return null; } public Class<?> classForName(String name, ClassLoader cl) throws ClassNotFoundException { return null; } Class<?> classForName(String name, ClassLoader[] cls) throws ClassNotFoundException { for(ClassLoader cl: cls) { if(cl != null) { try { Class<?> c = Class.forName(name, true, cl); if(c != null) return c; } catch (ClassNotFoundException e) { // we'll ignore this until all classloaders fail to locate the class } } } throw new ClassNotFoundException("Cannot find class: " + name); } ClassLoader[] getClassLoaders(ClassLoader cl) { return new ClassLoader[] { cl, defaultClassLoader, Thread.currentThread().getContextClassLoader(), getClass().getClassLoader(), systemClassLoader }; } }