什么是 Java ClassLoader?
用几个简单的句子来说,什么是Java ClassLoader,什么时候使用它,为什么?
好吧,我读了一篇维基文章。类装入器装入类。还行。因此,如果我包含jar文件并导入,ClassLoader就可以完成这项工作。
我为什么要为这个类加载器而烦恼?我从未使用过它,也不知道它的存在。
问题是,为什么类加载器类存在?另外,您如何在实践中使用它?(我知道,有案例存在。
用几个简单的句子来说,什么是Java ClassLoader,什么时候使用它,为什么?
好吧,我读了一篇维基文章。类装入器装入类。还行。因此,如果我包含jar文件并导入,ClassLoader就可以完成这项工作。
我为什么要为这个类加载器而烦恼?我从未使用过它,也不知道它的存在。
问题是,为什么类加载器类存在?另外,您如何在实践中使用它?(我知道,有案例存在。
摘自Sun的这个很好的教程:
用静态编译的编程语言(如 C 和 C++)编写的应用程序被编译为特定于本机的本机指令,并保存为可执行文件。将代码合并到可执行本机代码的过程称为链接 - 将单独编译的代码与共享库代码合并以创建可执行应用程序。这在动态编译的编程语言(如Java)中是不同的。在 Java 中,Java 编译器生成的.class文件保持原样,直到加载到 Java 虚拟机 (JVM) 中 - 换句话说,链接过程由 JVM 在运行时执行。类“根据需要”加载到 JVM 中。当一个装入的类依赖于另一个类时,该类也会被装入。
启动 Java 应用程序时,要运行的第一个类(或应用程序的入口点)是具有公共静态 void 方法的类,称为 main()。此类通常具有对其他类的引用,并且所有装入所引用类的尝试都由类装入器执行。
要了解这种递归类加载以及一般的类加载思想,请考虑以下简单类:
public class HelloApp {
public static void main(String argv[]) {
System.out.println("Aloha! Hello and Bye");
}
}
如果运行此类指定 -verbose:class 命令行选项,以便它打印正在加载的类,则将获得如下所示的输出。请注意,这只是部分输出,因为列表太长而无法在此处显示。
prmpt>java -verbose:class HelloApp
[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]
如您所见,首先加载应用程序类 (HelloApp) 所需的 Java 运行时类。
Java编程语言不断发展,使应用程序开发人员的生活更加轻松。这是通过提供 API 来完成的,这些 API 允许您专注于业务逻辑而不是基本机制的实现细节,从而简化您的生活。最近 J2SE 1.5 到 J2SE 5.0 的更改可以明显看出这一点,以反映 Java 平台的成熟度。
从 JDK 1.2 开始,内置于 JVM 中的引导类装入器负责装入 Java 运行时的类。此类装入器仅装入在引导类路径中找到的类,并且由于这些是受信任的类,因此不会像执行不受信任的类那样执行验证过程。除了引导类装入器之外,JVM 还有一个扩展类装入器,负责从标准扩展 API 装入类,还有一个系统类装入器,用于从常规类路径以及应用程序类装入类。
由于存在多个类装入器,因此它们在根是引导类装入器的树中表示。每个类装入器都有一个对其父类装入器的引用。当要求类装入器装入类时,它会在尝试装入项目本身之前查阅其父类装入器。父级依次咨询其父级,依此类推。因此,只是在祖先类装入器找不到当前类装入器所涉及的类之后。换句话说,使用委派模型。
这是一个抽象类,可以由需要扩展 JVM 动态加载类的方式的应用程序进行子类化。中的构造函数(及其子类)允许您在实例化新的类装入器时指定父级。如果未显式指定父级,则虚拟机的系统类装入器将被指定为缺省父级。换句话说,类使用委派模型来搜索类和资源。因此,ClassLoader 的每个实例都有一个关联的父类装入器,因此当请求查找类或资源时,在尝试查找类或资源本身之前,将任务委派给其父类装入器。ClassLoader 的方法在调用以装入类时按顺序执行以下任务:java.lang.ClassLoader
java.lang.ClassLoader
loadClass()
如果某个类已被装入,它将返回该类。否则,它将对新类的搜索委托给父类装入器。如果父类装入器找不到该类,则 调用该方法来查找并装入该类。如果父类装入器未找到该类,则该方法在当前类装入器中搜索该类。loadClass()
findClass()
finalClass()
原始文章中还有更多内容,它还向您展示了如何实现自己的网络类装入器,这回答了您为什么(以及如何)的问题。另请参阅 API 文档。
大多数 Java 开发人员永远不需要显式使用类装入器(除了装入资源,以便当它们捆绑在 JAR 中时它仍然有效),更不用说编写自己的类装入器了。
类加载器用于大型系统和服务器应用程序,用于执行如下操作: