您的位置:首页 > 移动开发

知识回顾10、类装载器学习一、类加载器的基本概念

2012-05-21 09:54 295 查看
类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java Applet 需要从远程下载 Java 类文件到浏览器中并执行。现在类加载器在 Web 容器和 OSGi 中得到了广泛的使用。一般来说,Java 应用的开发人员不需要直接同类加载器进行交互。Java 虚拟机默认的行为就已经足够满足大多数情况的需求了。不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试
ClassNotFoundException
NoClassDefFoundError
等异常。本文将详细介绍
Java 的类加载器,帮助读者深刻理解 Java 语言中的这个重要概念。下面首先介绍一些相关的基本概念。

类加载器基本概念

顾名思义,类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成
java.lang.Class
类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的
newInstance()
方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如
Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

java.lang.ClassLoader类的介绍

java.lang.ClassLoader
类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即
java.lang.Class
类的一个实例。除此之外,
ClassLoader
还负责加载 Java 应用所需的资源,如图像文件和配置文件等。不过本文只讨论其加载类的功能。为了完成加载类的这个职责,
ClassLoader
提供了一系列的方法,比较重要的方法如下表所示。关于这些方法的细节会在下面进行介绍。

方法说明
getParent()
返回该类加载器的父类加载器。
loadClass(String name)
加载名称为
name
的类,返回的结果是
java.lang.Class
类的实例。
findClass(String name)
查找名称为
name
的类,返回的结果是
java.lang.Class
类的实例。
findLoadedClass(String name)
查找名称为
name
的已经被加载过的类,返回的结果是
java.lang.Class
类的实例。
defineClass(String name, byte[] b, int off, int len)
把字节数组
b
中的内容转换成 Java 类,返回的结果是
java.lang.Class
类的实例。这个方法被声明为
final
的。
resolveClass(Class<?> c)
链接指定的 Java 类。
对于上表中给出的方法,表示类名称的
name
参数的值是类的二进制名称。需要注意的是内部类的表示,如
com.example.Sample$1
com.example.Sample$Inner
等表示方式。这些方法会在下面介绍类加载器的工作机制时,做进一步的说明。下面介绍类加载器的树状组织结构。
类加载器的树状组织结构

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。系统提供的类加载器主要有下面三个:

引导类加载器(Bootstrap):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自
java.lang.ClassLoader

扩展类加载器(ExtClassLoader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
系统类加载器(AppClassLoader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过
ClassLoader.getSystemClassLoader()
来获取它。
除了系统提供的类加载器以外,开发人员可以通过继承
java.lang.ClassLoader
类的方式实现自己的类加载器,以满足一些特殊的需求。

除了引导类加载器之外,所有的类加载器都有一个父类加载器。通过上表中给出的
getParent()
方法可以得到。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java 类如同其它的 Java 类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。下表中给出了一个典型的类加载器树状组织结构示意图,其中的箭头指向的是父类加载器。





下面代码清单一演示了类加载器的树状结构:

public class ClassLoaderTree {

public static void main(String[] args) {
ClassLoader loader = ClassLoaderTree.class.getClassLoader();
while (loader != null) {
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println(loader);//最后当loader=null的时候。这个时候loader代表的是引导类加载器BootStrap
}
}


输出结果:

sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null


第一个输出的是
ClassLoaderTree
类的类加载器,即系统类加载器。它是
sun.misc.Launcher$AppClassLoader
类的实例;第二个输出的是扩展类加载器,是
sun.misc.Launcher$ExtClassLoader
类的实例。需要注意的是这里并没有输出引导类加载器,这是由于有些 JDK 的实现对于父类加载器是引导类加载器的情况,
getParent()
方法返回
null
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息