Java类加载机制
类加载机制及SPI

类加载机制及SPI最近重温Java类加载及双亲委派机制,并写了⼀个SPI的例⼦从⽹上找了⼀张图⽚,对着图⽚及课堂笔记来梳理下。
⾸先java⾃带的类加载器分为BootStrapClassLoader(引导\启动类加载器),ExtClassLoader(扩展类加载器),AppClassLoader(应⽤程序类加载器)三种,此外还⽀持⽤户⾃⼰定义的⾃定义类加载器,加载的是⽤户⾃⼰指定的⽬录。
BootStrapClassLoader:jvm中,c++处理类加载的这套逻辑,被称为启动类加载器,是由c++编写的,在java中为null,加载的路径是Jre/lib/rt.jar, 在这个过程中会通过启动类加载器,来加载uncherHelper,并执⾏checkAndLoadMain,以及加载main函数所在的类,并启动扩展类加载器、应⽤类加载器ExtClassLoader: 扩展类加载器,加载的是Jre/lib/ext/*.jar,查看⽅式:public static void main(String[] args) {ClassLoader classLoader = ClassLoader.getSystemClassLoader().getParent();URLClassLoader urlClassLoader = (URLClassLoader) classLoader;URL[] urls = urlClassLoader.getURLs();for (URL url : urls) {System.out.println(url);}}AppClassLoader: 应⽤类加载器,加载⽤户程序的类加载器,加载的是CLASS_PATH中指定的所有jarpublic static void main(String[] args) {String[] urls = System.getProperty("java.class.path").split(":");for (String url : urls) {System.out.println(url);}System.out.println("---------------------------------------------------------");URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();URL[] urls1 = classLoader.getURLs();for (URL url : urls1) {System.out.println(url);}}双亲委派机制:类加载时,AppClassLoader 会先查看⾃⾝是否已经加载过当前class⽂件,如果加载过则直接返回,如果没有加载过,则委托他的⽗类(ExtClassLoader)尝试进⾏加载,ExtClassLoader也会先查看⾃⼰是否加载过,加载过则直接返回,没有加载过,则继续委派给BootStrapClassLoader,如果直⾄BootStrapClassLoader都没有加载过,则会AppClassLoader会尝试进⾏加载。
Java高级程序设计认证试卷

Java高级程序设计认证试卷(答案见尾页)一、选择题1. Java语言的特性包括哪些?A. 封装B. 多态C. 抽象D. 动态代理2. 在Java中,以下哪个关键字用于定义常量?A. finalB. staticC. constD. var3. Java中的集合框架包含以下哪些接口?A. CollectionB. ListC. SetD. Map4. Java的异常处理机制包括以下哪些关键字?A. tryB. catchC. finallyD. throw5. 以下哪个是Java反射机制中用于获取类信息的方法?A. getDeclaredMethods()B. getGenericSuperclass()C. getAnnotations()D. getComponentType()6. Java的泛型支持以下哪种类型转换?A. 自动装箱/拆箱B. 自动类型转换C. 强制类型转换D. 隐式类型转换7. Java的注解处理器用于执行哪些任务?A. 代码重构B. 类文件生成C. 性能优化D. 错误检查8. 在Java中,以下哪个关键字用于实现接口?A. implementsB. extendsC. implementsD. extends9. Java的序列化机制用于以下哪个目的?A. 恢复内存中的对象状态B. 实现跨平台的数据交换C. 提高数据安全性D. 降低数据存储效率10. Java的线程同步机制使用的关键字是?A. synchronizedB. volatileC. lockD. await11. Java语言有哪些基本数据类型?A. byteB. shortC. intD. long12. 在Java中,以下哪个关键字用于定义方法?A. privateB. staticC. finalD. abstract13. Java中的集合框架包括哪些接口和实现类?A. ListB. SetC. QueueD. Map14. Java中,哪个关键字用于实现继承?A. extendsB. implementsC. interfaceD. override15. 在Java中,什么是垃圾回收机制(Garbage Collection)?A. 一种自动内存管理技术B. 一种手动内存管理技术C. 一种动态数组技术D. 一种静态数组技术16. Java中,哪个关键字用于导入其他包或类库?A. importB. includeC. requireD. uses17. 在Java中,什么是异常处理机制?请简述。
dcevm原理 -回复

dcevm原理-回复【dcevm原理】一种支持在运行时替换Java类定义的虚拟机1. 引言dcevm(Dynamic Code Evolution VM)是一种特殊的Java虚拟机,它支持在运行时替换已加载的Java类定义。
传统的Java虚拟机在运行过程中无法修改已加载的类,这使得开发人员在改变类定义时,需要重启应用程序。
然而,dcevm的出现解决了这个问题,使得开发人员可以通过替换类定义而无需重启应用程序,提高了开发效率。
本文将深入探讨dcevm 的原理与实现。
2. Java类加载过程回顾在深入理解dcevm原理之前,我们需要先回顾一下Java类加载的过程。
当Java程序执行时,虚拟机会按照特定的顺序进行类加载,主要包括加载、链接和初始化三个阶段。
在加载阶段,虚拟机会从磁盘读取类的字节码,并生成对应的Class对象;在链接阶段,虚拟机会对类进行验证、准备和解析的操作;最后,在初始化阶段,虚拟机会执行类的静态初始化代码。
3. dcevm的设计理念dcevm的设计目标是支持在运行时替换Java类定义,避免应用程序重启。
为了实现这一目标,dcevm引入了一些新的概念和机制。
其中最重要的是HotSwap机制,即在运行时替换已加载的Java类定义。
通过HotSwap,开发人员可以在调试和测试阶段,及时修复或更新代码,快速迭代应用程序。
4. HotSwap机制的实现流程HotSwap机制的实现主要涉及以下几个步骤:- 备份原始类定义:在替换类定义之前,dcevm会在内部保存原始的类定义,以便需要时恢复。
- 加载新的类定义:开发人员通过一些手段(如IDE等工具)生成新的类定义,并将其加载到虚拟机中。
- 类验证:虚拟机会对新加载的类进行验证,以确保其与原始类定义兼容。
- 类替换:当新的类定义通过验证后,dcevm将会替换原始的类定义,并且在替换完成后,重新初始化该类的实例。
5. 实时调试和代码热部署dcevm的HotSwap机制不仅仅支持简单的类替换,还可以辅助实时调试和代码热部署。
类加载的三种方式

类加载的三种⽅式类加载分为动态加载和静态加载。
动态加载是从外存储器中加载类,⼀般类加载机制分析的也是动态加载。
⽽静态加载本质上是从内存中创建类的实例对象,此时类已经被加载到内存中。
⼀.静态加载通过new关键字来创建Test的实例对象。
⼆.动态加载1.通过Class.forName()来加载类,然后调⽤类的newInstance()⽅法实例化对象。
2.通过类加载器的loadClass()⽅法来加载类,然后调⽤类的newInstance()⽅法实例化对象。
这⾥有⼏个需要⽐较的地⽅:1.通过new关键字实例化类的对象和通过Class.forName()加载类是当前类加载器,即this.getClass.getClassLoader,只能在当前类路径或者导⼊的类路径下寻找类。
⽽⽤指定的classLoader来加载类可以从当前路径外寻找类,这⾥的classLoader甚⾄可以⽤户⾃定义。
2.我们知道类加载机制的三个过程主要是加载-->连接-->初始化。
Class.forName()实际调⽤的是Class.forName(className,true,this.getClass.getClassLoader),第⼆个参数表⽰加载完后是否⽴即初始化,第三个参数即前⽂提到的表⽰是当前类加载器。
classLoader.loadClass()实际调⽤的是classLoader.loadClass(className,false),第⼆个参数表⽰加载完成后是否连接,即⽤此⽅法加载类,加载完成后不会去初始化,⽽⽤Class.forName()加载类加载完成后可以被初始化。
所以有些类如果加载完成后需要⽴即被初始化则必须使⽤Class.forName()。
例如在加载数据库驱动时,⼀般⽤Class.forName("com.mysql.jdbc.Driver")。
这是因为该驱动有⼀个在静态代码块中注册驱动的过程,所以需要被初始化。
java 类里的loadclass用法

java 类里的loadclass用法Java中的loadClass()方法是在Class类中定义的一个方法,用于动态加载类。
在程序运行时可以根据类的全限定名来加载指定的类文件,并返回对应的Class对象。
loadClass()方法的语法如下:`public Class<?> loadClass(String name) throws ClassNotFoundException`这个方法可以在当前的ClassLoader中通过类的全限定名来加载指定的类文件。
如果找不到该类文件,则会抛出ClassNotFoundException异常。
下面将详细介绍loadClass()方法的使用以及相关概念和实例。
1. 理解Java类加载器在介绍loadClass()方法之前,先来了解一下Java类加载器。
类加载器是Java虚拟机(JVM)的一个组件,用于从文件系统、网络或其他来源加载Java类文件。
Java虚拟机通过类加载器来定位并加载类文件,将其转换为一个Class对象,并存放在方法区(即运行时数据区域之一)。
一个Java类加载器通常是由一个ClassLoader类的实例来表示的。
Java 提供了三种内置的ClassLoader:- Bootstrap ClassLoader:负责加载Java核心类库,是虚拟机的一部分,无法直接获取。
- Extension ClassLoader:负责加载Java扩展库,如javax包下的类。
- System ClassLoader:也称为Application ClassLoader,负责加载应用程序的类,可以通过ClassLoader.getSystemClassLoader()来获取。
2. 使用loadClass()方法动态加载类loadClass()方法是ClassLoader类的一个原生方法,可以通过子类来调用。
在调用loadClass()方法时,会按照ClassLoader的委派模型进行类的加载。
classloader加载原理

classloader加载原理classloader是java中一个比较重要的类加载器,每一个程序和类都会存在一个classloader,classloader有三种主要的工作:加载类的二进制字节流、连接、初始化。
一、Classloader加载机制1、首先classloader会按照特定的方式去搜索类文件,当它找到了相应的类文件之后,它会将这个类文件转换成为二进制字节流,这里涉及到编译程序,classloader会使用编译程序将源程序编译成可执行文件。
2、接下来classloader会将这些二进制字节流存储在内存中,然后classloader会连接这些字节流,这一步是它将这些字节流组装成一个完整的类文件,这里涉及到类的加载,这些加载的类可以被访问,但是它们的代码还未被执行。
3、最后classloader会初始化这些加载的类,这一步就是它将这些类的代码执行,这里classloader会执行所有类变量的初始化,同时也会执行所有静态代码块的内容,最后我们就可以得到一个完整的类文件。
二、Classloader的三种类型1、Bootstrap Classloader:它是用来加载JRE的核心类的,它的实现是C++语言,它的加载范围是从<JAVA_HOME>lib下面开始,这个类加载器不需要程序员编写任何外部类。
2、Extension Classloader:它是用来加载扩展类的,从<JAVA_HOME>libext开始加载,它继承自Bootstrap Classloader,这种类加载器也不需要程序员手动编写任何外部类。
3、Application Classloader:它是用来加载程序类的,它继承自Extension Classloader,它从ClassPath(来自系统变量或者命令行参数)所指定的路径中加载类,但是它不会加载扩展类。
三、Classloader安全机制1、安全性验证:Classloader在加载类的时候会先验证这个类文件,检查它是否符合class文件格式,其次classloader会过滤掉由它本身加载的不安全的类,这涉及到安全管理器的配置,例如:可以设置它只能加载特定的域名下的类文件。
javaagent加载机制分析

javaagent加载机制分析在启动和运⾏期都可以加载agent代理,在启动的时候可通过-javaagent参数来执⾏agent代理,⽽在运⾏期就是通过attach这种机制动态load了。
如果在vm启动过程中加载agent,那么会在vm初始化过程中先执⾏libinstrument.dylib⾥InvocationAdapter.c的Agent_OnLoad⽅法,这⾥主要是实例化agent,解析agent的MF⽂件,将相关属性取出来,并注册jvmti的⼀些回调函数,在vm初始化完成之后,会通过回调函数去实例化Instrumentation实现对象,设置ClassFileLoadHook函数,并调⽤Pre-Main指定类的premain⽅法。
C代码1. JNIEXPORT jint JNICALL2. Agent_OnLoad(JavaVM *vm, char *tail, void * reserved) {3. JPLISInitializationError initerror = JPLIS_INIT_ERROR_NONE;4. jint result = JNI_OK;5. JPLISAgent * agent = NULL;6.7. initerror = createNewJPLISAgent(vm, &agent);8. if ( initerror == JPLIS_INIT_ERROR_NONE ) {9. int oldLen, newLen;10. char * jarfile;11. char * options;12. jarAttribute* attributes;13. char * premainClass;14. char * agentClass;15. char * bootClassPath;16.17. /*18. * Parse <jarfile>[=options] into jarfile and options19. */20. if (parseArgumentTail(tail, &jarfile, &options) != 0) {21. fprintf(stderr, "-javaagent: memory allocation failure.\n");22. return JNI_ERR;23. }24.25. /*26. * Agent_OnLoad is specified to provide the agent options27. * argument tail in modified UTF8. However for 1.5.0 this is28. * actually in the platform encoding - see 5049313.29. *30. * Open zip/jar file and parse archive. If can't be opened or31. * not a zip file return error. Also if Premain-Class attribute32. * isn't present we return an error.33. */34. attributes = readAttributes(jarfile);35. if (attributes == NULL) {36. fprintf(stderr, "Error opening zip file or JAR manifest missing : %s\n", jarfile);37. free(jarfile);38. if (options != NULL) free(options);39. return JNI_ERR;40. }41.42. premainClass = getAttribute(attributes, "Premain-Class");43. if (premainClass == NULL) {44. fprintf(stderr, "Failed to find Premain-Class manifest attribute in %s\n",45. jarfile);46. free(jarfile);47. if (options != NULL) free(options);48. freeAttributes(attributes);49. return JNI_ERR;50. }51.52. /*53. * Add to the jarfile54. */55. appendClassPath(agent, jarfile);56.57. /*58. * The value of the Premain-Class attribute becomes the agent59. * class name. The manifest is in UTF8 so need to convert to60. * modified UTF8 (see JNI spec).61. */62. oldLen = (int)strlen(premainClass);63. newLen = modifiedUtf8LengthOfUtf8(premainClass, oldLen);64. if (newLen == oldLen) {65. premainClass = strdup(premainClass);66. } else {67. char* str = (char*)malloc( newLen+1 );68. if (str != NULL) {69. convertUtf8ToModifiedUtf8(premainClass, oldLen, str, newLen);70. }71. premainClass = str;72. }73. if (premainClass == NULL) {74. fprintf(stderr, "-javaagent: memory allocation failed\n");75. free(jarfile);76. if (options != NULL) free(options);77. freeAttributes(attributes);78. return JNI_ERR;79. }80.81. /*82. * If the Boot-Class-Path attribute is specified then we process83. * each relative URL and add it to the bootclasspath.84. */85. bootClassPath = getAttribute(attributes, "Boot-Class-Path");86. if (bootClassPath != NULL) {87. appendBootClassPath(agent, jarfile, bootClassPath);88. }89.90. /*91. * Convert JAR attributes into agent capabilities92. */93. convertCapabilityAtrributes(attributes, agent);94.95. /*96. * Track (record) the agent class name and options data97. */98. initerror = recordCommandLineData(agent, premainClass, options);99.100. /*101. * Clean-up102. */103. free(jarfile);104. if (options != NULL) free(options);105. freeAttributes(attributes);106. free(premainClass);107. }108.109. switch (initerror) {110. case JPLIS_INIT_ERROR_NONE:111. result = JNI_OK;112. break;113. case JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT:114. result = JNI_ERR;115. fprintf(stderr, "ng.instrument/-javaagent: cannot create native agent.\n"); 116. break;117. case JPLIS_INIT_ERROR_FAILURE:118. result = JNI_ERR;119. fprintf(stderr, "ng.instrument/-javaagent: initialization of native agent failed.\n"); 120. break;121. case JPLIS_INIT_ERROR_ALLOCATION_FAILURE:122. result = JNI_ERR;123. fprintf(stderr, "ng.instrument/-javaagent: allocation failure.\n");124. break;125. case JPLIS_INIT_ERROR_AGENT_CLASS_NOT_SPECIFIED:126. result = JNI_ERR;127. fprintf(stderr, "-javaagent: agent class not specified.\n");128. break;129. default:130. result = JNI_ERR;131. fprintf(stderr, "ng.instrument/-javaagent: unknown error\n");132. break;133. }134. return result;135. }如果在运⾏期通过attach api来load agent,那么会在收到load指令之后,会调⽤InvocationAdapter.c的Agent_OnAttach⽅法,其实现基本和Agent_OnLoad⼀致,只是还会调⽤Agent-Class的agentmain⽅法,还有点不同就是对vmint事件没有再关注(都运⾏期了,关注也没⽤),⽽是直接对ClassFileLoad关注,也不会再调⽤Pre-Main指定的类的premain⽅法(顾名思义,是在执⾏main⽅法之前执⾏的,所以运⾏期搞执⾏Pre-Main的class也不妥)。
classloader运行机制

ClassLoader是Java中的类加载器,它的主要工作是将Class加载到JVM中。
以下是其运行机制:
1. 父优先加载机制:ClassLoader采用了一种“父优先”的等级加载机制,也就是说,当一个类需要被加载时,ClassLoader会首先检查它的父类是否已经被加载。
如果父类已经被加载,那么就直接使用父类的类对象;如果父类还没有被加载,那么就先加载父类,然后再加载当前类。
这种机制也适用于同一加载器中加载的类之间的依赖关系。
2. 类加载过程:当一个类需要被加载时,ClassLoader会首先找到这个类的class文件,并把这个文件包含的字节码加载进内存。
然后,它会对这些字节码进行解析和初始化。
在解析过程中,ClassLoader 会将类字节码重新解析成JVM统一要求的对象格式,并生成类的Class对象。
3. 显示和隐式加载:ClassLoader有两种加载方式:显示加载和隐式加载。
隐式加载是指不需要代码调用类加载器加载需要的类,而是通过JVM自动加载。
显示加载则需要调用类加载器来加载类。
比如,使用类Class中的forName()方法、ClassLoader中的loadClass()方法或findSystemClass()方法等来加载类。
总的来说,ClassLoader在Java中扮演着非常重要的角色,它负责将Class加载到JVM中,并审查每个类应该由谁来加载,以及将类字节码重新解析成JVM统一的对象格式。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
或者 public class MyClassLoader extends ClassLoader{
public MyClassLoader(){ super(getClass().getClassLoader());
} }
第一种方法更为常用,因为在构造方法中使用 getClass() 方法是不提倡的,因为对象初 始化仅在构造方法结束后才会完成。因此,如果正确设置了类加载器的父类加载器,不论 什么时候从类加载器实例请求一个类时,如果此类加载器不能加载此类,则首先会交给它 的父类加载器处理。如果此父类加载器也不能加载那个类,则又会交给上一层的父类加载 器,依此类推。但是如果 findBootstrapClass0()方法也未能加载那个类时,就会唤醒 findClass() 去处理。findClass()的默认的实现是抛 ClassNotFoundException 异常。所以开发者需要继承 ng.ClassLoader 来实现用户自编写的类加载器。findClass()默认的实现如下:
Java 类加载机制(一)
译:ayi 译文疏漏,请多多指点
原文:/pub/a/onjava/2005/01/26/classloading.html
注:因内容太多,分为一、二两篇文章
类加载是 java 特性的一个很重要的部分。尽管,java 中“advanced topics”的发展,使 java 的类加载机制地位有所下降。但每位编程者都应该知道这部分的工作机制,以及怎样去配 合其工作。这可以使我们节省很多时间,而不必要浪费在调试ClassNotFoundException, ClassCastException, 等。
设置父类加载器,我们有两种方法,在 ClassLoader 的构造方法中。 public class MyClassLoader extends ClassLoader{
public MyClassLoader(){ super(MyClassLoader.class.getClassLoader());
载器的正常工作来说都非常重要。在这里,最重要的是怎样正确的设置父类加载器。类加 载器的父类加载器实例会负责加载此类加载器类。(记住:一个类加载器本身也是一个类。) 在一个类加载器外部请求一个类时,使用 loadClass() 方法。这个方法的具体工作,我们可 以从源代码来看:
protected synchronized Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException{
比如,如果我们试图得到一个核心 java 运行时类的一个类加载器,我们将得到 null 值,如 下: log(ng.String.class.getClassLoader()); 下面要说到的是 java 扩展类加载器。在 java.ext.dirs 路径下面,我们可以放 java 扩展类库, 这样我们可以获得超出 java 核心运行时类的特性。扩展类加载器(ExtClassLoader)将会加 载 java.ext.dirs 目录下的所有 .jar 文件。开发者可以为自己的应用增加新的 .jar 文件 或者 类 库,只要他把它们添加到 java.ext.dirs 目录下面以至于能被扩展类加载器找到。
类加载器
在 java 中,每个类都会被 ng.ClassLoader 的一个实例加载。ClassLoader 类处于 ng
包下面,开发者可以自由的创建它的子类,添加自己功能的类加载器。
每当敲入 java MyMainClass,一个新的 JVM 开始时,引导类加载器(bootstrap class loader ) 首先会把 java 中的一些关键类,像 ng.Objent,和运行时的代码载入内存。这些运行 时类打包在 JRE\lib\rt.jar 文件中。因为是一个本地的接口,我们并不能从 java 文档中得到 引 导 类 加 载 器 ( bootstrap class loader ) 信 息 。 也 正 是 这 个 原 因 , 引 导 类 加 载 器 (bootstrap class loader )的表现也根据 JVM 的不同而异。
这篇文章将从最基本的开始,比如代码和数据的关系,以及他们怎么样关系起来形成一 个实例或者对象。然后将会说到,java 中怎样通过类加载器把代码加载到 JVM 中,以及 java 中实现的主要的几种类型的类加载器。在这篇文章中,然后我们将会了解到 java 类加载机 制的内幕,我们将使用最基本的代码来描述,这些代码执行于类加载器之后,但在加载一 个类之前。在接下来的部分将使用一些例子来证实,对于开发者继承和开发自己的类加载 器的必要性。接着将告诉你们怎样编写自己的类加载器,以及怎样使用它们去创建一个一 般的能加载包括远程客户端辅助代码的类加载器引擎,以及怎样把它在 JVM 中定义,实例 化,然后执行。习惯上,把 J2EEspecific components 中说明的作为 java 类加载的规范,这 篇文章正是从这本手册总结来的。
的字段 class,这个字段表示的就是一个 ng.Class 型的实例。因为它是 public 类型的, 我们可以通过标识符来访问它,像这样:
ng.Class klass = Myclass.class;
只要一个类被加载到 JVM,相同的类(强调:相同的类)将不会被重复加载。这将产 生一个问题,什么才是相同的类?一个对象有一种特定状态和标识,对象总是与它所属类 联系在一起,与这种状况相似,一个被加载到 JVM 中类也有特定的标识,接下来我们就阐 述:
在 java 中,一个类通过认证的类全名来唯一标识。认证的类全名是由包名和类名两部 分组成。但是在一个类被加载到 JVM 中则是通过认证的类全名,还有加载这个类的加载器 来唯一标识。因此,一个类的类名为 C1,包名为 Pg,被类加载器类 KClassLoader 的一个 实例 k1 加载,则 C1,也就是 C1.class ,的类实例,在 JVM 中将被解释为(C1,Pg,k1)。 这就意味着两个不同的类加载器实(Cl, Pg, kl1) 和 (Cl, Pg, kl2) ,加载的类在 JVM 中将有不 同的类实例对象,不是类型可比型(typecompatible)的。在 JVM 中有多少个类加载器实 例呢?下面,我们将讲解这个。
图 1 展 示 了 一 个 带 有 main 方 法 的 应 用 程 序 类 MyMainClass 。 正 如 前 面 所 说 的 , MyMainClass.class 将被 AppClassLoader 加载 ,MyMainClass 创建两个加载器类实例, CustomClassLoader1 和 CustomClassLoader2,他们都能从某些资源(比如说:网络)中加载 第四个类 Target 的字节码。这就意味着 Target 这个类的定义超出了应用程序的 class path 或 者扩展 class path 范围。在这种 情况下,如果 MyMainClass 让客户加载器实例去加载 Target 类。Target 将同时被 CustomClassLoader1 和 CustomClassLoader2 加载和定义。在 java 中这样就会有严重的问题。如果在 Target 中包含一段静态(static)的初始化代码,如果我 们要求这段代码执行且仅贝被执行一次,在我们目前的情况下,这段代码将被执行两次。 在两个 CustomClassLoader 中,都执行了一次。如果 Target 被两个 CustomClassLoader 同时 初始化,他将会有两个实例 target1 和 target2 ,正如下面图 1 所示的,target1 和 target2 是不 可比的。也就是说,在 java 中不能执行这段代码:
// First check if the class is already loaded Class c = findLoadedClass(name); if (c == null) {
try { if (parent != null) { c = parent.loadClass(name, false); } else { c = findBootstrapClass0(name); }
在 Sun 的 java 指南中,文章“理解扩展类加载”(Understanding Extension Class Loading) 对以上三个类加载器路径有更详尽的解释,这是其他几个 JDK 中的类加载器
.URLClassLoader java.security.SecureClassLoader java.rmi.server.RMIClassLoader sun.applet.AppletClassLoader
protected Class<?> findClass(String name)
throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
深入 findClass()方法,类加载器需要从其它资源获取字节码。这些资源可以是文件系统、网 络 URL、数据库、其它的可以把字节码转换为流的应用程序,或者能够产生与 java 特性相 适应的字节码的类似资源。你可以使用BCEL (Byte Code Engineering Library),它能非常方便 的根据运行时的迹象创建类 。BCEL 已经成功的应用在了一些地方,如编译器、优化程序、 模糊程序(ob节码被重新获取,findClass()
类和数据
一个类代表一段要执行的代码,然而数据则代表与这些代码相关联的某种状态。状态可 以改变,代码不能改变。我们把一种特定状态与一个类关联起来时,就得到了这个类的一 个实例。所以同一个类的不同实例有不同的状态,但都参照相同的代码。在 java 中,一个 类通常它的代码就包含在一个 .class 文件中,虽然其中也包括异常。然而,在 java 运行时, 每个类都会构造一个超类对象(firstclass object),它们其实是 ng.Class 的实例。不 论何时编译一个 java 文件,编译器都会在编译后的字节码中嵌入一个 public, static, final 型