1、Java虚拟机的类的装载2009-06-12 16:02 haobobest haobobest博客 我要评论(0) 字号:T | T本文分为三个大的部分,对 Java虚拟机的类的装载进行了讲述,其中最主要的是 Java虚拟机的类装载实现与应用和 Java虚拟机的类装载原理,最后对整篇文章的总结。AD:一、引言Java虚拟机(JVM)的类装载就是指将包含在类文件中的字节码装载到 JVM中, 并使其成为 JVM一部分的过程。JVM 的类动态装载技术能够在运行时刻动态地加载或者替换系统的某些功能模块, 而不影响系统其他功能模块的正常运行。本文将分析 JVM中的类装载系统,探讨 JVM中类装载的原理
2、、实现以及应用。二、Java 虚拟机的类装载实现与应用2.1 装载过程简介所谓装载就是寻找一个类或是一个接口的二进制形式并用该二进制形式来构造代表这个类或是这个接口的 class对象的过程,其中类或接口的名称是给定了的。当然名称也可以通过计算得到,但是更常见的是通过搜索源代码经过编译器编译后所得到的二进制形式来构造。在 Java中,类装载器把一个类装入 Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下:装载:查找和导入类或接口的二进制数据;链接:执行下面的校验、准备和解析步骤,其
3、中解析步骤是可以选择的;校验:检查导入类或接口的二进制数据的正确性;准备:给类的静态变量分配并初始化存储空间;解析:将符号引用转成直接引用;初始化:激活类的静态变量的初始化 Java代码和静态 Java代码块。至于在类装载和虚拟机启动的过程中的具体细节和可能会抛出的错误,请参看Java虚拟机规范以及深入 Java虚拟机。由于本文的讨论重点不在此就不再多叙述。2.2 装载的实现JVM中类的装载是由 ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的 Java运行时系匙榧 涸鹪谠诵惺辈檎液妥叭肜辔募 睦唷?BR在 Java中,ClassLoader 是一个抽象
4、类,它在包 java.lang中,可以这样说,只要了解了在 ClassLoader中的一些重要的方法,再结合上面所介绍的 JVM中类装载的具体的过程,对动态装载类这项技术就有了一个比较大概的掌握,这些重要的方法包括以下几个:loadCass 方法 loadClass(String name ,boolean resolve)其中 name参数指定了JVM需要的类的名称,该名称以包表示法表示,如 Java.lang.Object;resolve 参数告诉方法是否需要解析类,在初始化类之前,应考虑类解析,并不是所有的类都需要解析,如果JVM只需要知道该类是否存在或找出该类的超类,那么就不需要解析。
5、这个方法是ClassLoader 的入口点。defineClass 方法这个方法接受类文件的字节数组并把它转换成 Class对象。字节数组可以是从本地文件系统或网络装入的数据。它把字节码分析成运行时数据结构、校验有效性等等。findSystemClass 方法 findSystemClass 方法从本地文件系统装入文件。它在本地文件系统中寻找类文件,如果存在,就使用 defineClass将字节数组转换成 Class对象,以将该文件转换成类。当运行 Java应用程序时,这是 JVM 正常装入类的缺省机制。resolveClass 方法 resolveClass(Class c)方法解析装入的类
6、,如果该类已经被解析过那么将不做处理。当调用 loadClass方法时,通过它的 resolve 参数决定是否要进行解析。findLoadedClass 方法当调用 loadClass方法装入类时,调用 findLoadedClass 方法来查看 ClassLoader是否已装入这个类,如果已装入,那么返回 Class对象,否则返回NULL。如果强行装载已存在的类,将会抛出链接错误。2.3 装载的应用一般来说,我们使用虚拟机的类装载时需要继承抽象类 java.lang.ClassLoader,其中必须实现的方法是 loadClass(),对于这个方法需要实现如下操作:(1) 确认类的名称;(2
7、) 检查请求要装载的类是否已经被装载;(3) 检查请求加载的类是否是系统类;(4) 尝试从类装载器的存储区获取所请求的类;(5) 在虚拟机中定义所请求的类;(6) 解析所请求的类;(7) 返回所请求的类。所有的 Java 虚拟机都包括一个内置的类装载器,这个内置的类库装载器被称为根装载器(bootstrap ClassLoader)。根装载器的特殊之处是它只能够装载在设计时刻已知的类,因此虚拟机假定由根装载器所装载的类都是安全的、可信任的,可以不经过安全认证而直接运行。当应用程序需要加载并不是设计时就知道的类时,必须使用用户自定义的装载器(user-defined ClassLoader)。下
8、面我们举例说明它的应用。1. public abstract class MultiClassLoader extends ClassLoader 2. . 3. public synchronized Class loadClass(String s, boolean flag) 4. throws ClassNotFoundException 5. 6. 7. Class class1 = (Class)classes.get(s); 8. 9. 10. if (class1 != null) return class1; 11. try 12. class1 = super.findSy
9、stemClass(s); 13. return class1; 14. 15. catch(ClassNotFoundException _ex) 16. System.out.println(“ Not a system class.“); 17. 18. 19. 20. byte abyte0 = loadClassBytes(s); 21. if (abyte0 = null) throw new ClassNotFoundException(); 22. 23. class1 = defineClass(null, abyte0, 0, abyte0.length); 24. if
10、(class1 = null) throw new ClassFormatError(); 25. if (flag) resolveClass(class1); 26. 27. classes.put(s, class1); 28. System.out.println( “ Returning newly loaded class.“); 29. 30. 31. return class1; 32. 33. . 34. 三、Java 虚拟机的类装载原理前面我们已经知道,一个 Java应用程序使用两种类型的类装载器:根装载器(bootstrap)和用户定义的装载器(user-defined)
11、。根装载器是 Java虚拟机实现的一部分,举个例子来说,如果一个 Java虚拟机是在现在已经存在并且正在被使用的操作系统的顶部用 C程序来实现的,那么根装载器将是那些 C程序的一部分。根装载器以某种默认的方式将类装入,包括那些 Java API的类。在运行期间一个 Java程序能安装用户自己定义的类装载器。根装载器是虚拟机固有的一部分,而用户定义的类装载器则不是,它是用 Java语言写的,被编译成 class文件之后然后再被装入到虚拟机,并像其它的任何对象一样可以被实例化。 Java 类装载器的体系结构如下所示:Java的类装载模型是一种代理(delegation)模型。当 JVM 要求类装载
12、器CL(ClassLoader)装载一个类时,CL 首先将这个类装载请求转发给他的父装载器。只有当父装载器没有装载并无法装载这个类时,CL 才获得装载这个类的机会。这样, 所有类装载器的代理关系构成了一种树状的关系。树的根是类的根装载器(bootstrap ClassLoader) , 在 JVM 中它以“null“表示。除根装载器以外的类装载器有且仅有一个父装载器。在创建一个装载器时, 如果没有显式地给出父装载器, 那么 JVM将默认系统装载器为其父装载器。下面针对各种类装载器分别进行详细的说明。根(Bootstrap) 装载器:该装载器没有父装载器,它是 JVM实现的一部分,从sun.bo
13、ot.class.path装载运行时库的核心代码。扩展(Extension) 装载器:继承的父装载器为根装载器,不像根装载器可能与运行时的操作系统有关,这个类装载器是用纯 Java代码实现的,它从 java.ext.dirs (扩展目录)中装载代码。系统(System or Application) 装载器:装载器为扩展装载器,我们都知道在安装 JDK的时候要设置环境变量(CLASSPATH ),这个类装载器就是从 java.class.path(CLASSPATH 环境变量)中装载代码的,它也是用纯Java代码实现的,同时还是用户自定义类装载器的缺省父装载器。小应用程序(Applet) 装载
14、器:装载器为系统装载器,它从用户指定的网络上的特定目录装载小应用程序代码。在设计一个类装载器的时候,应该满足以下两个条件:对于相同的类名,类装载器所返回的对象应该是同一个类对象如果类装载器 CL1将装载类 C的请求转给类装载器 CL2,那么对于以下的类或接口,CL1和 CL2应该返回同一个类对象:a)S 为 C的直接超类;b)S 为 C的直接超接口;c)S 为 C的成员变量的类型;d)S 为 C的成员方法或构建器的参数类型;e)S 为 C的成员方法的返回类型。每个已经装载到 JVM中的类都隐式含有装载它的类装载器的信息。类方法getClassLoader 可以得到装载这个类的类装载器。一个类装
15、载器认识的类包括它的父装载器认识的类和它自己装载的类,可见类装载器认识的类是它自己装载的类的超集。注意我们可以得到类装载器的有关的信息,但是已经装载到 JVM中的类是不能更改它的类装载器的。Java中的类的装载过程也就是代理装载的过程。比如:Web 浏览器中的 JVM需要装载一个小应用程序 TestApplet。JVM 调用小应用程序装载器 ACL(Applet ClassLoader)来完成装载。ACL 首先请求它的父装载器, 即系统装载器装载 TestApplet是否装载了这个类, 由于 TestApplet不在系统装载器的装载路径中, 所以系统装载器没有找到这个类, 也就没有装载成功。接
16、着 ACL自己装载 TestApplet。ACL 通过网络成功地找到了TestApplet.class 文件并将它导入到了 JVM中。在装载过程中, JVM 发现 TestAppet是从超类 java.applet.Applet继承的。所以 JVM再次调用 ACL来装载 java.applet.Applet类。ACL又再次按上面的顺序装载 Applet类, 结果 ACL发现他的父装载器已经装载了这个类, 所以 ACL就直接将这个已经装载的类返回给了 JVM , 完成了 Applet类的装载。接下来,Applet类的超类也一样处理。最后, TestApplet 及所有有关的类都装载到了 JVM中。四、结论类的动态装载机制是 JVM的一项核心技术, 也是容易被忽视而引起很多误解的地方。本文介绍了 JVM中类装载的原理、实现以及应用,尤其分析了 ClassLoader的结构、用途以及如何利用自定义的 ClassLoader装载并执行 Java类,希望能使读者对 JVM中的类装载有一个比较深入的理解
Copyright © 2018-2021 Wenke99.com All rights reserved
工信部备案号:浙ICP备20026746号-2
公安局备案号:浙公网安备33038302330469号
本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。