最近在读周志明的《深入理解Java虚拟机》,随手记录一些吧。
类与类加载器
对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。这句话可以表达得更通俗一些:比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。
这里所指的“相等”,包括代表类的Class对象的equals()方法、isAssignableFrom()方法、isInstance()方法的返回结果,也包括使用instanceof关键字做对象所属关系判定等情况。
类加载器的划分
- 启动类加载器(Bootstrap ClassLoader):这个类加载器负责将存放在
\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(这里只识别jar文件)类库加载到虚拟机内存中。 - 扩展类加载器(Extension ClassLoader):这个加载器负责加载
\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。 - 应用程序类加载器(Application ClassLoader):这个类加载器试ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称为系统类加载器。它负责加载用户类路径(ClassPath)上所指定的类库。一般情况这个也是程序中默认的类加载器。
双亲委派模型
如图
这里的类加载器之间的父子关系一般不会用继承实现,而是使用组合来复用父加载器的代码。
双亲委派模型的工作过程是:如果一个类加载器收到了加载类的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传递到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时。子加载器才会尝试自己去加载。
使用双亲委派模型的好处:
Java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是一个类。
试着这样考虑,如果没有这样机制,每个类加载器自行加载的话,系统中就会出现多个不同的Object类,应用程序会变得混乱。
java.lang.ClassLoader中的关于类加载的部分代码如下:
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;
}
}
转载请标注原文链接