Java ClassLoader
Java ClassLoader 是 Java运行时环境 的一部分,它动态地将Java类加载到 Java虚拟机中。 因为有了类加载器,Java运行时系统不需要了解文件和文件系统。Java类并不是一下子就加载到内存中,而是在应用程序需要时才加载。这时, JRE 会调用 Java ClassLoader ,这些ClassLoader会动态地将类加载到内存中。
Java中ClassLoaders的类型
不是所有的类都由一个ClassLoader加载。根据类的类型和类的路径,决定加载该特定类的ClassLoader。要知道加载一个类的ClassLoader,可以使用 _ getClassLoader()_ 方法。所有的类都是根据它们的名字来加载的,如果没有找到这些类,就会返回 NoClassDefFoundError 或 ClassNotFoundException。 一个Java Classloader有 三种类型。
- BootStrap ClassLoader: Bootstrap Classloader是一个机器代码,当JVM调用它时,它就会启动操作。它不是一个java类。它的工作是加载第一个纯Java ClassLoader。Bootstrap ClassLoader从 _ rt.jar_ 的位置加载类。Bootstrap ClassLoader没有任何父级ClassLoader。它也被称为 原始的ClassLoader。
- Extension ClassLoader: Extension ClassLoader是Bootstrap ClassLoader的子代,从相应的JDK扩展库中加载核心java类的扩展。它从 _ jre/lib/ext_ 目录或由系统属性 _ java.ext.dirs_ 指向的任何其他目录中加载文件 _ 。_
- 系统类加载器: 应用程序类加载器也被称为系统类加载器。它加载在环境变量 _ CLASSPATH、-classpath或-cp命令行选项_ 中找到的应用程序类型的类。应用程序类加载器是扩展类加载器的一个子类。
注意 :ClassLoader委托层次模型总是按照Application ClassLoader->Extension ClassLoader->Bootstrap ClassLoader的顺序运行。Bootstrap ClassLoader总是被赋予较高的优先级,接下来是Extension ClassLoader,然后是Application ClassLoader。
Java ClassLoader的功能原则
功能原则是Java ClassLoader工作所依据的 一组规则 或特征。有 三个功能原则 ,它们是。
- 委托模型 :Java虚拟机和Java ClassLoader使用一种叫做 委托层次算法 的算法,将类加载到Java文件中。ClassLoader根据委托模型给出的一组操作来工作。它们是
- ClassLoader总是遵循 Delegation Hierarchy原则。
- 每当JVM遇到一个类,它就会检查该类是否已经被加载。
- 如果该类已经被加载到方法区,那么JVM就会继续执行。
- 如果该类不在方法区,那么JVM会要求Java ClassLoader子系统加载该特定的类,然后ClassLoader子系统将控制权移交给 Application ClassLoader。
- Application ClassLoader然后将请求委托给Extension ClassLoader, Extension ClassLoader 又将请求委托给 Bootstrap ClassLoader。
- Bootstrap ClassLoader将在Bootstrap classpath(JDK/JRE/LIB)中搜索。如果该类是可用的,那么它就会被加载,如果不是,请求会被委托给Extension ClassLoader。
- Extension ClassLoader在Extension Classpath(JDK/JRE/LIB/EXT)中搜索该类。如果该类是可用的,那么它将被加载,如果不是,请求将被委托给应用程序ClassLoader。
- Application ClassLoader在Application Classpath中搜索该类。如果该类是可用的,那么它就被加载,如果不是,就会产生一个 ClassNotFoundException 异常。
- 可见性原则 : 可见性原则 指出,由父类加载器加载的类对子类加载器是可见的,但由子类加载器加载的类对父类加载器是不可见的。假设一个GEEKS.class被Extension ClassLoader加载,那么该类只对Extension ClassLoader和Application ClassLoader可见,而对Bootstrap ClassLoader不可见。如果再次尝试使用Bootstrap ClassLoader加载该类,就会出现 _ java.lang.ClassNotFoundException异常。_
- 唯一性属性 : 唯一性属性 确保类是唯一的,没有重复的类。这也确保了由父类加载器加载的类不会被子类加载器加载。如果父类加载器不能够找到该类,那么只有当前的实例才会自己尝试这样做。
Java.lang.ClassLoader的方法
在JVM对类提出请求后,为了加载一个类,需要遵循几个步骤。类是按照委托模式加载的,但有几个重要的方法或函数在加载类时起着至关重要的作用。
- loadClass(String name, boolean resolve) : 这个方法用来加载JVM引用的类。它将类的名称作为一个参数。这个方法的类型是loadClass(String, boolean)。
- defineClass() : defineClass()方法是一个 最终 方法,不能被重写。这个方法用来定义一个字节数组作为一个类的实例。如果该类是无效的,它将抛出 ClassFormatError。
- findClass(String name) : 这个方法用来查找一个指定的类。这个方法只找到但不加载该类。
- findLoadedClass(String name) : 该方法用于验证JVM引用的类是否已经被加载。
- Class.forName(String name, boolean initialize, ClassLoader loader) : 该方法用于加载类以及初始化类。这个方法还提供了选择任何一个ClassLoader的选项。如果ClassLoader参数为NULL,则使用Bootstrap ClassLoader。
例子: 下面的代码在类被加载之前被执行。
protected synchronized Class<?>
loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class c = findLoadedClass(name);
try {
if (c == NULL) {
if (parent != NULL) {
c = parent.loadClass(name, false);
}
else {
c = findBootstrapClass0(name);
}
}
catch (ClassNotFoundException e)
{
System.out.println(e);
}
}
}
注意 :如果一个类已经被加载了,它将返回该类。否则,它将寻找新类的工作委托给父类加载器。如果父类加载器没有找到该类, loadClass() 会调用 findClass() 方法来寻找并加载该类。如果父类加载 器 没有找到该类,findClass( ) 方法会在当前的 ClassLoader 中搜索该类 。