Java类加载器负责加载Java类。当我们导入包和JAR(Java Archive)文件时,ClassLoader会自动将这些文件加载到我们的程序中。
为什么要注意ClassLoader呢?虽然你可能没有直接使用过它,但在一些特殊情况下,了解和掌握ClassLoader仍然非常重要。
因此,ClassLoader类存在的原因是为了方便Java程序员动态地加载和链接Java类。在实践中使用ClassLoader的案例也不少。
这段内容摘自Sun的精彩教程:
使用C和C++等静态编译语言编写的应用程序会被编译成本地、机器特定的指令并保存为可执行文件。将代码合并为可执行的本机代码的过程称为链接 - 即将分别编译的代码与共享库代码合并以创建可执行应用程序。而在Java等动态编译语言中,情况有所不同。在Java中,Java编译器生成的.class文件保持原样,直到加载到Java虚拟机(JVM)中——换句话说,链接过程是由JVM在运行时执行的。类是根据需要在JVM中加载的。当已加载的类依赖于另一个类时,那个类也会被加载。
当启动Java应用程序时,第一个要运行的类(或应用程序的入口点)是具有名为main()的public static void方法的类。此类通常引用其他类,所有尝试加载引用类的操作由类装入器执行。
为了感受这种递归类加载以及类加载思想的总体概念,请考虑以下简单的类:
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来简化您的生活,使应用程序开发人员的生活变得更加轻松。这是通过最近将J2SE 1.5更改为J2SE 5.0以反映Java平台的成熟而实现的。
从JDK 1.2开始,内置于JVM中的引导类加载器负责加载Java运行时的类。此类加载器仅加载在引导类路径中找到的类,并且由于这些是受信任的类,因此不执行与不受信任的类相同的验证过程。除了引导类加载器之外,JVM还具有扩展类加载器,负责从标准扩展API中加载类,并且系统类加载器从一般类路径以及您的应用程序类中加载类。
由于存在多个类加载器,因此它们在树中表示为其根为引导类加载器。每个类加载器都引用其父类加载器。当要求类加载器加载类时,在尝试自行加载该项之前,它会咨询其父类加载器。父级再咨询其父级,依此类推。因此,使用委派模型。只有在所有祖先类加载器无法找到该类时,当前类加载器才会参与。
java.lang.ClassLoader
是一个抽象类,可以由需要扩展JVM动态加载类方式的应用程序进行子类化。在java.lang.ClassLoader
(及其子类)中的构造函数允许您在实例化新类加载器时指定父级。如果您没有显式指定父级,则虚拟机的系统类加载器将分配为默认父级。换句话说,ClassLoader类使用委派模型搜索类和资源。因此,每个ClassLoader实例都有一个关联的父类加载器,因此在要求查找类或资源时,任务会委托给其父类加载器,然后再尝试查找该类或资源本身。ClassLoader的loadClass()方法在调用以加载类时按顺序执行以下任务:
如果已经加载了一个类,则返回它。 否则,将新类的搜索委托给父级类加载器。 如果父级类加载器未找到类,则loadClass()调用findClass()方法查找并加载类。 如果父级类加载器未找到类,则finalClass()方法将在当前类加载器中搜索该类。
原始文章中还有更多内容,其中还介绍了如何实现自己的网络类加载器,回答了您关于为什么(以及如何)的问题。另请参阅API文档。
大多数Java开发者永远不需要显式地使用类加载器(除非为了加载资源以便在JAR包中使用),更不用说编写自己的类加载器了。
类加载器主要应用于大型系统和服务器应用程序,用于以下一些功能:
ClassLoader
是Java中用于加载类文件的类。Java代码被javac
编译器编译成类文件,JVM通过执行类文件中编写的字节码来执行Java程序。
ClassLoader负责从文件系统、网络或任何其他来源加载类文件。在Java中有三个默认的类加载器,分别是Bootstrap、Extension和System或Application类加载器。
类加载器是JVM的一个功能组件,它将类数据从“.class”文件或通过网络加载到堆中的方法区。
看起来像是JVM的一个不可或缺的部分,但作为终端Java用户,我为什么应该关心呢?原因如下:
每个类加载器都有自己的命名空间,由特定类加载器调用的类进入其命名空间。
由两个不同类加载器调用的类将无法相互访问,从而增强了安全性。
类加载器父子委派机制确保Java API类永远不能被未经授权的代码攻击。
详情请看这里
类加载器是分层的。当一个已经在JVM中运行的类通过名称引用另一个类时,该类会被引入到JVM中。
第一个被加载的类是如何加载的?
第一个被加载的类是通过你的类中声明的static main()
方法来加载的。随后加载的所有类都是由已经加载并运行的类加载的。
类加载器创建了一个命名空间。所有的JVM都包括至少一个嵌入在JVM中的类加载器,称为原始(或引导)类加载器。这是一件事情,我们将看看非原始类加载器。JVM内部有钩子允许使用用户定义的类加载器代替原始类加载器。以下是JVM创建的类加载器。
引导(原始) 这个类加载器不可重新加载。它加载JDK内部类、java.*包(通常加载rt.jar和i18n.jar)。 扩展 这个类加载器不可重新加载。它从JDK扩展目录(通常是JRE的lib/ext)加载jar文件。 系统 这个类加载器不可重新加载。它从系统类路径加载类。
BootstrapClassLoader
负责使这些类可用,即将这些类加载到内存中。
下一个任务是将任何外部库/JAR加载到内存中,以便应用程序正常工作。 ExtClassLoader
负责此任务。此类加载器负责加载在java.ext.dirs路径中提到的所有.jar文件。
第三个也是最重要的类加载器是AppClassLoader
。应用程序类加载器负责加载在java.class.path系统属性中提到的类文件。
还要注意,默认的ClassLoader实现可以被覆盖,使您能够以有用和有趣的方式自定义JVM,从而完全重新定义如何将类文件引入系统。
查看它以了解有关Java类加载器的更多信息。
类加载器
ClassLoader
是 Java 运行时环境(JRE)的一部分,它可以将类(环境对象 - java.lang.Class
和文件 .class
)动态加载到 JVM(Java 虚拟机)中。JRE 使用 延迟类加载(按需)来减少内存占用。当应用程序需要某个类时,JRE 会要求 ClassLoader 加载该类。
ClassLoader 类有一个层次结构:
classpath
[关于] 或命令行选项(-cp、-classpath)中加载。此外,您还可以为特定情况创建自己的 ClassLoader 类。例如,从某个存储库加载类、处理版本控制、卸载和安全性。
为了检查到底是谁在加载你的类,可以使用getClassLoader()
方法
SomeClass.class.getClassLoader()
child classloader find in cache
if not
parent classloader find in cache
if not
parent classloader try to load
if not
child classloader try to load