近期学习java的classloader(类加载器),有必要记录下,好记性不如烂笔头,这里略去代码测试部分,纯粹记录脑中所想,如有纰漏、错误请大家及时提出,也是帮我提高。
系统类加载器:
当java虚拟机(jvm.dll)启动后,会创建三个类加载器BootStrapClassLoader、ExtClassLoader、AppClassLoader,它们是java虚拟机的一部分,一直逗留在内存中,直到java虚拟机终止才会在内存中消失,它们都有自己的管辖目录范围,在管辖内寻找类(.class文件)来加载。
BootStrapClassLoader:c++编写,在java中表现形式为null。
ExtClassLoader:java编写,源代码在sun.misc.Launcher类中,它是一个内部类。
AppClassLoader:java编写,源代码也在sun.misc.Launcher类中,它也是一个内部类。
简单理解,ExtClassLoader和AppClassLoader被设计成单例模式,在内存中分别只有一个对象。
用户创建类加载器:
用java编写的类加载器都要直接或者间接继承类java.lang.ClassLoader,包括用户(用户指程序员)自己编写的,也包括系统类加载器ExtClassLoader和AppClassLoader。
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { 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(); } } if (resolve) { resolveClass(c); } return c; } }
protected ClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader()); } protected ClassLoader(ClassLoader parent) { this(checkCreateClassLoader(), parent); }
具体细节查看javadoc或者sourcecode.
类加载器有两种,一种是系统类加载器(在内存中只有一份),另一种是用户自己定义类加载器(在内存中可以有很多份,根据new的次数)。
class文件在内存中的形态:
同一个class文件可以被不同的类加载器对象加载,每个类加载器对象只能对它加载一次(如果用loadClass方法的话)。这样看来class文件在内存中可能会有很多份,每一份都是一个class对象,大家都知道在new的时候就是根据这个class对象为模板创建对象的,当内存里有很多class对象的时候,new的时候会根据系统类加载器(BootStrapClassLoader、ExtClassLoader、AppClassLoader)加载的那个class对象为模板创建对象,效果和其他份class对象的newInstance()一样。class对象newInstance()的时候返回一个Object对象,如果对它向下转型为具体类的时候可能会出现奇怪的现象,见 http://www.iteye.com/problems/77669 在向下转型的时候,对比的是class对象是否相等,不同的类加载器加载的class对象是不同的,是各占一个内存空间的,所以出现连接中的问题。
上面的内容都是根据现象推出来的,还没有足够的证据支持,下一步继续学习jvm规范,希望能找到依据,内部实现机制还是很多不了解。