首页 > 代码库 > Java的类载入器

Java的类载入器

每次创建Java类的实例时,都必须现将类载入到内存中。Java虚拟机使用类载入器来载入需要的类。一般情况下,类在如期会在一些Java核心类库,以及环境变量CLASSPATH中指明的目录中搜索相关类。如果在这些位置它都找不到要载入的类,就会抛出java.lang.ClassNotFoundException异常。

从J2SE 1.2开始,JVM使用了3中类载入器来载入所需要的类,分别是引导类载入器(bootstrap class loader)、扩展类载入器(extension class loader)和系统类载入器(system class loader)。3种类载入器之间是父子继承关系,其中引导类载入器位于层次结构的最上层,系统类载入器位于最下层。

引导类载入器用于引导启动JVM。当调用javax.exe程序时,就会启动引导类载入器。引导类载入器是使用本地代码来实现的,因为用它来载入运行JVM所需要的类,以及所有的Java核心类,例如java.lang包和java.io包下的类。启动类载入器会在rt.jar和i18n.jar等Java包中搜索要载入的类。引导类载入器要从哪些库中搜索类依赖于JVM和操作系统的版本。

扩展类载入器负责载入标准扩展目录中的类。这有利于程序开发,因为程序员值需要将JAR文件复制到扩展目录中就可以被类载入器搜索到。扩展类库依赖于JDK供应商的具体实现。SUN公司的JVM的标准扩展目录是/jdk/jre/lib/ext。

系统类载入器是默认的类载入器,它会搜索在环境变量CLASSPATH中指明的路径和JAR文件。

那么,JVM使用的是哪个类载入器呢?答案在于类载入器的代理模型。使用代理模型可以有效地解决类载入过程中的安全性问题。每当需要载入一个类的时候,会首先调用系统类载入器。但是,它并不会立即载入某个类。相反,它会将载入类的任务交给其父载入器,即扩展类载入器,而扩展类载入器又会将载入任务交给其父类载入器,即引导类载入器。因此,引导类载入器总是会首先执行载入某个类的任务。如果引导类载入器找不到需要载入的类,那么扩展类载入器会尝试载入该类。如果扩展类载入器也找不到这个类,就会轮到系统类载入器继续执行载入任务。如果系统类载入器还是找不到这个类,则会抛出java.lang.ClassNotFoundException异常。那么为什么要执行这样也给循环过程呢?

代理模型的重要用途就是为了解决类载入过程中的安全性问题。如你所知,可以使用安全管理器来限制某个类对某个路径的访问。现在,某个恶意用户编写了一个名为java.lang.Object的类,它可以访问硬盘中的任意目录。由于JVM是信任java.lang.Object类的,这样,它就不会监视这个类的活动。结果是,如果这个自定义java.lang.Object允许载入,安全管理器就这样被轻易的绕过了。幸运的是,由于使用了代理模型,这种情况是不会发生的。

当程序中的某个地方调用了自定义的java.lang.Object类时,系统类载入器会将载入任务委托给扩展类载入器,继而会被交给引导类载入器。引导类载入器搜索器核心库,找到标准的java.lang.Object类,并将之实例化。结果是,自定义java.lang.Object类并没有载入。

关于Java中类载入机制的一件重要的事情是,可以通过继承抽象类java.lang.ClassLoader类编写自己的类载入器。

使用自定义的类载入器可以实现如下的需求:

1.在载入类中指定某些规则

2.缓存已将载入的类

3.实现类的预载入,方便使用


本文出自 “起航” 博客,请务必保留此出处http://fblsky.blog.51cto.com/1752592/1535771