初探Java类加载机制的奥秘
1.在JDK1.2之后,类加载是通过委托来完成的,这意味着如果类加载器找不到该类,它将请求父类加载器来执行这项任务。所有类加载器的根是系统类加载器,默认情况下,它将从本地文件系统加载类。今天,我们来讨论这些机制在jvm中是如何工作的。我们假设有一个类字节码文件(比如Hello.class文件),那么它是如何加载到应用程序中并形成类对象的呢?我们这篇文章的目的就是解释这个问题。
Java.lang包中有一个ClassLoader类,ClassLoader的基本目标是为类请求提供服务。当JVM需要使用一个类时,它根据类的名称向ClassLoader请求这个类,然后ClassLoader试图返回一个表示这个类的类对象。通过覆盖对应于该过程不同阶段的方法,您可以创建一个定制的类加载器。有一个loadClass(字符串名称,布尔解析)方法,它是类加载器的入口点。在jdk1.2之后,loadclass方法会默认调用findClass方法。有关详细信息,请参考API文档。我们写的ClassLoader主要是为了覆盖以上两种方法。让我们回到刚才的问题。我们如何读取字节码文件并把它形成一个类对象?ClassLoader中有一个方法,Classdefine class (string name,byte[] b,int off,int len),答案在这里。我们把一个类字节码文件(比如Hello.class)读入一个字节数组byte [] b,转换成一个类对象,而这些数据可以来自文件、网络等。太神奇了:)
DefineClass管理JVM的许多复杂、神秘和依赖于实现的方面——它将字节码分析成运行时数据结构,验证有效性等等。别担心,你不用自己写。事实上,即使你想覆盖它,你也不能覆盖它,因为它已经被标记为最终版本。
其他一些方法:
FindSystemClass方法:从本地文件系统加载文件。它在本地文件系统中寻找一个类文件,如果存在,就用defineClass把原来的字节转换成类对象把文件转换成类。
FindClass方法:jdk1.2调用这个新方法后loadClass的默认实现。find的用途包括了你的类加载器的所有特殊代码,不需要复制其他代码(比如特殊方法失败时调用系统类加载器)。
getSystemClassLoader:如果您重写findClass或loadClass,GetSystemClassLoader使您能够将系统类加载器作为实际的类加载器对象来访问(而不是固定地从findSystemClass中调用它)。
GetParent:为了将类请求委托给父类加载器,这个新方法允许类加载器获得它的父类加载器。当定制的类加载器无法通过特殊方法找到类时,可以使用这个方法。
ResolveClass:可以不完全加载(不解析)或完全加载(解析)。在编写自己的loadClass时,我们可以调用resolveClass,这取决于loadClass的resolve参数的值。
findLoadedClass:充当缓存。当请求loadClass加载类时,它调用这个方法检查ClassLoader是否加载了类,这样可以避免重载现有类带来的麻烦。应该首先调用此方法。
二、工作流程:
1)调用findLoadedClass(String)查看是否有加载的类。如果没有,就用那个特殊的魔法方式来获取原始字节。
2)通过父类加载器调用loadClass方法。如果父类加载器为空,则默认加载该类,即系统类加载器。
3)调用findClass(String)查找类,得到类;
4)如果loadClass的resolve参数值为true,则调用resolveClass解析类对象。
5)如果还没有类,则返回ClassNotFoundException。
6)否则,将该类返回给调用者。
位律师回复
0条评论