`
nuistcc
  • 浏览: 82862 次
社区版块
存档分类
最新评论

Java类加载机制浅析

阅读更多
Java中的类加载机制主要有类加载器完成。类加载器可以说是Java语言的一项创新,也是Java语言流行的重要原因之一,称为了Java体系中一块重要的基石。

类与类加载器
    类加载器虽然只用于实现类的加载动作,但它在Java程序中起到的作用却远远不限于类加载阶段。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性,每一个类加载器都拥有一个独立的类名称空间。也就是说,比较两个类是否“相等”,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。

双亲委派模型
   从Java虚拟机的角度来讲,只存在两种不同的类加载器:一种的启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现,是虚拟机自身的一部分;另一种就是所有其他的类加载器,这些类加载器都由Java语言实现,独立于虚拟机外部,并且全部都继承自抽象类java.lang.ClassLoader.
    从Java开发人员的角度来看,类加载器还可以划分的更加细致一些,绝大部分Java程序都会使用到以下3种系统提供的类加载器

(1)启动类加载器(Bootstrap ClassLoader)
    这个类加载器负责将存放在\lib目录中的,或者被-Xbootclasspath参数所指定的路径中,并且是被虚拟机识别的类库加载到虚拟机内存中。
    启动类加载器无法被Java程序直接引用。
(2)扩展类加载器(Extension ClassLoader)
    这个类加载器有sun.misc.Launcher$ExtClassLoader实现,它负责加载\lib\ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发这可以直接使用扩展类加载器。
(3)应用程序类加载器(Application ClassLoader)
     这个类加载器由sun.misc.Launcher$AppClassLoader实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。
     它负责加载用户类路径(ClassPath)上所指定的类库,开发者可以直接使用者个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

   我们的应用程序都是由这3种类加载器相互配合进行加载的,如果有必要,还可以加入自己定义的类加载器。这些类加载器之间的关系一般如下图所示。

   这种层次关系称为类加载器的双亲委派模型(Parents Delegation Model)。
   双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。这里的类加载器之间的父子关系一般不会以继承的关系来实现,二是都使用组合关系来复用父加载器的代码。
   双亲委派模型的工作过程是:如果一个类加载器手到了类加载的请求,它首先不会自己去尝试加载这个类,二是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的类加载请求最终都应用传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。
   使用双亲委派模型来组织类加载器之间的关系,有一个显而易见的好处就是Java类随着它的类加载器一起具备了一种带有优先级的层次关系。
   例如类java.lang.Object,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有使用双亲委派模型,由各个类加载自行去加载的话,如果用户自己编写了一个称为java.lang.Object的类,并放在程序的ClassPath中,那系统中将会出现多个不同的Object类,Java类型体系中最基础的行为也就无法保证,应用程序也将变得一片混乱。
    双亲委派模型对于保证Java程序的稳定运行很重要,但它的实现却非常简单,实现双亲委派的代码都集中在java.lang.ClassLoader的loadClass()方法中。
    源码如下:先检查是否已经被加载过,若没有加载则调用父加载器的loadClass()方法,若父加载器为空则默认使用启动类加载器作为父加载器。如果父加载器加载失败,抛出ClassNotFoundException异常后,再调用自己的findClass()方法进行加载。
protected synchronized Class<?> loadClass(String name, boolean resolve)
	throws ClassNotFoundException
    {
	// First, check if the class has already been loaded
	Class c = findLoadedClass(name);
	if (c == null) {
	    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.
	        c = findClass(name);
	    }
	}
	if (resolve) {
	    resolveClass(c);
	}
	return c;
    }


  • 大小: 37.5 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics