类加载器

来源:互联网 发布:数据库不能附加 编辑:程序博客网 时间:2024/06/06 02:39

概述

  虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类,实现这个动作的代码模块称为“类加载器”。
  对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟中的唯一性。说通俗一些,比较两个类是否“相等”,只有在两个类是由同一个类加载器的前提之下才有意义,否则,即使这两个类来源于同一个class文件,只要加载它的类加载器不同,那这两个类必定不相等。这里所指的“相等”包括代表类的Class对象的equal方法、isAssignableFrom()、isInstance()方法及instance关键字返回的结果

加载器类型

从虚拟机的角度来讲,只存在两种不同的类加载器:

  1. 一种是启动类加载器(Bootstrap ClassLoader),这个类加载器用 C++ 语言实现, 是虚拟机自身的一部分。
  2. 另一种就是所有其它的类加载器, 这些类加载器用Java 语言实现,独立于虚拟机外部,并且全都继承自抽象类java.lang.ClassLoader。

从Java 开发人员的角度来看,类加载器还可以划分的更细致一些,绝大多数Java 程序都会用到以下3种系统提供的类加载器:

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

双亲委派模式

  注意:上述三个JDK提供的类加载器虽然是父子类加载器关系,但是没有使用继承,而是使用了组合关系。
  从JDK1.2开始,java虚拟机规范推荐开发者使用双亲委派模式(ParentsDelegation Model)进行类加载,其加载过程如下:

  1. 如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器去完成。
  2. 每一层的类加载器都把类加载请求委派给父类加载器,父加载器为空则默认使用启动类加载器作为父加载器,直到所有的类加载请求都应该传递给顶层的启动类加载器。
  3. 如果顶层的启动类加载器无法完成加载请求,子类加载器尝试去加载,如果连最初发起类加载请求的类加载器也无法完成加载请求时,将会抛出ClassNotFoundException,而不再调用其子类加载器去进行类加载。

优点

  双亲委派模型的优点在于越是基础的类,会被越上层的加载器进行加载,例如类java.lang.Objet,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object类在程序的各种类加载器环境下中都是同一个类。即使自定义了自己的类加载器,强行用defineClass()方法去加载一个以“java.lang”开头的类也不会成功,会抛出java.lang.SecurityException:Prohibited package name:java.lang异常。

原创粉丝点击