一个类加载器是一个负责加载类的对象,给定一个类的二进制名称,类加载器尝试查找或生成组成该类定义的数据信息。典型的是将这个名称转换成文件名称而后从文件系统中读取类文件
每个类对象包含一个定义它的类加载器。数组类的类对象不是经过类加载器建立;由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 }; } }