摘自Sun的这个不错的教程:
动机
用静态编译的编程语言(例如C和C ++)编写的应用程序被编译为本地的,机器特定的指令,并保存为可执行文件。将代码组合成可执行的本机代码的过程称为链接-
将单独编译的代码与共享库代码合并以创建可执行应用程序。在动态编译的编程语言(例如Java)中,这是不同的。在Java中,由Java编译器生成的.class文件将保持原样,直到加载到Java虚拟机(JVM)中为止-
换句话说,链接过程由JVM在运行时执行。将类“按需”加载到JVM中。当加载的类依赖于另一个类时,该类也将被加载。
启动Java应用程序时,要运行的第一个类(或应用程序的入口点)是带有称为main()的公共静态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 FilesJavajre1.5.0librt.jar][Opened C:Program FilesJavajre1.5.0libjsse.jar][Opened C:Program FilesJavajre1.5.0libjce.jar][Opened C:Program FilesJavajre1.5.0libcharsets.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 2平台中的类加载器
Java编程语言不断发展,使应用程序开发人员的生活每天都变得更加轻松。这是通过提供API来完成的,这些API通过允许您专注于业务逻辑而不是基本机制的实现细节来简化您的生活。为了反映Java平台的成熟,最近将J2SE
1.5更改为J2SE 5.0可以证明这一点。
从JDK
1.2开始,JVM内置的引导类加载器负责加载Java运行时的类。该类加载器仅加载在引导类路径中找到的类,并且由于它们是受信任的类,因此不会像对不信任的类那样执行验证过程。除了引导类加载器之外,JVM还具有扩展类加载器,用于从标准扩展API加载类,以及系统类加载器,用于从常规类路径以及应用程序类加载类。
由于有多个类加载器,因此它们在树中表示,其根是引导类加载器。每个类加载器都有对其父类加载器的引用。当要求类加载器加载类时,它会在尝试加载项目本身之前先咨询其父类加载器。父级依次咨询其父级,依此类推。因此,只有在所有祖先类加载器都找不到该类后,当前类加载器才涉及。换句话说,使用了委托模型。
java.lang.ClassLoader类
的
java.lang.ClassLoader是,可以由需要延长在其中JVM动态加载类的方式应用作为子类的抽象类。
java.lang.ClassLoader实例化新的类加载器时,(及其子类)中的构造函数允许您指定父级。如果您未明确指定父级,则会将虚拟机的系统类加载器指定为默认父级。换句话说,ClassLoader类使用委托模型来搜索类和资源。因此,ClassLoader的每个实例都有一个关联的父类加载器,因此当请求查找类或资源时,在尝试查找该类或资源本身之前,将任务委派给其父类加载器。
loadClass()当调用ClassLoader
的方法以加载类时,它按顺序执行以下任务:
如果已经加载了一个类,它将返回它。否则,它将对新类的搜索委托给父类加载器。如果父类加载器找不到该类,则
loadClass()调用该方法
findClass()以查找和加载该类。
finalClass()如果父类加载器找不到该类,则该方法在当前类加载器中搜索该类。
原始文章中还有更多内容,它还向您展示了如何实现自己的网络类加载器,它回答了有关原因(以及如何)的问题。另请参阅API文档。



