基本原理

所有类都由类装载器载入,载入内存中的类对应一个 java.lang.Class 实例。

已被加载的类由该类的类加载器实例与该类的全路径名的组合标识。设有 packagename.A Class ,分别被类加载器 CL1 CL2 加载,则系统中有两个不同的 java.lang.Class 实例: <CL1, packagename.A> <CL2, packagename.A>

存在一个 Bootstrap Loader (以下简称为 BL ),由 C++ 写成,负责在虚拟机启动后一次

性加载 Java 基础类库中的所有类。其他的类装载器由 Java 写成,都是 java.lang.ClassLoader 的子类。

BL 之外的所有类装载器都有一个 parent 属性,指向其父装载器。查阅 java.lang.ClassLoader 的源码,不难发现类装载器的委托装载方式。

 

     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 = findBootstrapClass0(name);

                   }

              } catch (ClassNotFoundException e) {

                  // If still not found, then invoke findClass in order

                  // to find the class.

                  c = findClass(name);

              }

          }

          if (resolve) {

              resolveClass(c);

          }

          return c;

    }

       对于给定的类名,首先检查自己是否已加载过该类。如果没有,则首先通过父装载器加载(如果 parent==null ,则直接通过 BL 来加载,相当于 BL 是其父装载器)。如果父装载器也无法装载,才真正调用自己的 findClass() 方法来装载。

       Java 基础类在 Java 虚拟机启动后由 BL 一次性载入。构成 Java 应用程序的其它类在程序运行过程中由不同类装载器按需通过 loadClass() 方法装载。

Java 程序启动过程中的类装载器

当执行“ java XXX.class ”时, java.exe 首先找到 JRE Java Runtime Environment ),接着找到位于 JRE 之中的 jvm.dll ,最后载入 jvm.dll 并启动虚拟机。

虚拟机一启动,先做一些初始化动作,如获取系统参数等,然后产生 BL BL 加载 Java 基础类,这些类都存放在 JRE 中的 lib 目录下,可由 System.getProperty(“sun.boot.class.path”) 列出,如:

 

C:\Program Files\Java\jre1.5.0_09\lib\rt.jar;

C:\Program Files\Java\jre1.5.0_09\lib\i18n.jar;

C:\Program Files\Java\jre1.5.0_09\lib\sunrsasign.jar;

C:\Program Files\Java\jre1.5.0_09\lib\jsse.jar;

C:\Program Files\Java\jre1.5.0_09\lib\jce.jar;

C:\Program Files\Java\jre1.5.0_09\lib\charsets.jar;

C:\Program Files\Java\jre1.5.0_09\classes

       BL 然后创建 sun.misc.Launcher$ExtClassLoader ExtClassLoader 是定义于 sun.misc.Launcher 之内的内部类,继承自 java.lang.URLClassLoader )的实例(以下简称 EL )和 sun.misc.Launcher$AppClassLoader AppClassLoader 是定义于 sun.misc.Launcher 之内的内部类,继承自 URLClassLoader )的实例(以下简称 AL ),并将 EL parent 属性设置为 null AL parent 属性设置为 EL

       EL 在程序运行过程中按需加载保存在 JRE 的“ \lib\ext ”目录下的类。该目录可由 System.getProperty(“java.ext.dirs”) 读出,如

 

C:\Program Files\Java\jre1.5.0_09\lib\ext

       AL 在程序运行过程中按需加载的类搜索路径则是从系统参数 java.class.path 取出的字符串。 java.class.path 是由我们在执行 java.exe 时,利用 -cp -classpath CLASSPATH 环境变量所决定。我们应用程序用到的非 JRE 提供类的搜索路径一般都配置在 java.class.path 中。

什么时候装载类,由什么类装载器装载

1.  Java 基础类由 BL 在虚拟机启动时一次性载入。

2.  包含 main() 的入口类由 AL loadClass() 方法载入。

3.  new 关键字创建一个类的实例。该类由运行时刻包含该 new 语句的类实例的类装载器( ClassLoader.getCallerClassLoader() )的 loadClass() 方法载入。

4.  调用 Class.forName() 方法。完整的 forName() 函数版本有一个 ClassLoader 参数,用于指定用什么类装载器来装载指定类。

 

    public static Class<?> forName(String name, boolean initialize,

                 ClassLoader loader) throws ClassNotFoundException

       对于 public static Class<?> forName(String className) 版本,是由运行时刻包含该语句的类实例的类装载器( ClassLoader.getCallerClassLoader() )的 loadClass() 方法载入。

5.  调用某个 ClassLoader 实例的 loadClass() 方法。通过该 ClassLoader 实例的 loadClass() 方法载入。应用程序可以通过继承 ClassLoader 实现自己的类装载器。

6 .装载一个类时,首先要装载该类的基类及其接口。