Java中的ClassLoader
Java中类的加载过程(如Dog类):
- 通过类型信息定位Dog.class文件。
- 载入Dog.class文件,创建相应的Class对象。
- 执行父类的静态字段定义时初始化语句和父类的静态初始化块。
- 执行子类的静态字段定义时初始化语句和子类的静态初始化块。
- 当使用new Dog()方式时,在堆上为Dog对象分配存储空间,并清零分配的存储空间。
- 执行父类的字段定义时初始化语句和父类的构造函数。
- 执行子类的字段定义时初始化语句和子类的构造函数。
(参考Java编程思想,部分是自己测试的结果,还没有看到相关资料,这个顺序和C#的顺序好像有比较大的差别)
我们知道每个Java类编译后会生成一个.class文件,里面除了存储了类的字节码之外,还存储了和该类对应的Class对象的信息(包含一些用于反射的信息)。在JVM中,通过类加载器(ClassLoader)来实现Class对象的创建。
在Object类中有public的getClass()方法,我们可以通过该方法获取与之对应的Class对象。在获取类对应的Class对象后,我们就可以通过newInstance()方法或者通过获取其Constructor的方法来创建该类的实例,也可以通过Class对象获取类或实例相关的更多信息,如方法,字段等,即反射的功能。另外我们也可以通过Class.forName()方法,通过传入类字符串的方式来创建类的实例。(通过Class对象创建类实例和通过forName方法创建类实例是否有联系呢?这两种创建类的实例和直接通过new创建类实例是否也有联系呢?)
然而Dog.class文件是如何定位的?Dog.class文件是如何被加载并解析的?Class对象又是如何生成的呢?这就是ClassLoader需要解决的问题,也是这篇文章中接下来要讲述的。
ClassLoader的工作原理
在Java内部实现了三种类型的ClassLoader:Bootstrap ClassLoader,Extension ClassLoader, System ClassLoader。这三个ClassLoader通过parent形成一条单向链,其中Bootstrap处于链尾,而System ClassLoader处于链头。
Bootstrap ClassLoader
Bootstrap ClassLoader用于在启动JVM时加载类,以使JVM能正常工作,因而它是用Native代码实现的,最早被创建出来,处于最底层。
Bootstrap ClassLoader将搜索Java核心库(%JAVA_HOME%\jre\lib),如rt.jar、i18n.jar等,在这些核心库中包含了Java的核心类,即Bootstrap ClassLoader用于加载Java的核心类,包括java.lang、java.io等包中的类。
Extension ClassLoader
Extension ClassLoader位于链的中间层,它将搜索特定的标准扩展目录。该标准扩展目录在不同的JVM实现中不一定相同,在sun的JVM中,它是%JRE_HOME% \lib\ext,具体路径可以通过java.ext.dirs系统属性值获取。该标准扩展目录存在的目的在于扩展和共享,应用程序厂商可以将部分共享库放置于此,而不是各自程序的目录下的多份拷贝。在开发过程中,我们也可以把部分常用的库放置于此,而不必每次都去配置环境。
System ClassLoader
System ClassLoader位于链的最顶层,它将搜索CLASSPATH中配置的目录和jar文件。
三种ClassLoader的协同工作
既然系统中有三种不同的ClassLoader,那么一个类的加载是用那个ClassLoader呢?在Java中,是通过“代理模型(delegation model)”来决定使用哪个ClassLoader来加载类的(读取.class文件,并创建相应的Class对象)。当一个类需要被加载的时候,系统默认通过System ClassLoader来加载该类;然而System ClassLoader并不立即加载该类,它会将加载的行为代理给其parent去加载,只有当其parent不能加载该类的时,System ClassLoader才去搜索CLASSPATH中的目录和jar文件以加载该类,若找到对应的.class文件,则加载该类,否则抛出ClassNotFoundException。当它将加载的行为代理给Extension ClassLoader并最终代理给Bootstrap ClassLoader的时候,他们也做的是相似的事情。从设计的角度,这其实就是一种职责链模式(Chain of Responsibility Pattern)。
那么Java为什么需要这种代理模型呢?答案是出于安全的考虑。Java是一种安全的编程语言,它会对每个加载的类执行安全检查,但是对Java核心库中的类是不执行安全检查的(即他们是受JVM信赖的)。(什么是安全检查?以我现在所知,就是用户可以通过security manager来控制特定目录的访问权限,如何使用这些控制将会是另一个主题。对安全检查是否还有其他的呢?)那么假如用户可以加载自己编写的和核心库同名的类(如java.lang.Object),那么这些用户编写的类就可以绕过安全检查,从而为一些恶意用户提供了一种破坏的途径。然而在使用这种代理模型后,类的加载首先会代理到Bootstrap ClassLoader中实行加载,如果它发现当前核心类库中可以加载对应的类,系统会加载核心库中的类,而不会加载用户编写的类。
但是如果只是这样,还不足以保证类的加载的安全。因为用户完全可以定义自己的ClassLoader,在自己的ClassLoader中破坏这种代理模型,那么用户自己写的java.lang.Object就可以被加载了。为了解决这个问题,在Java中认为两个类名相同的实例,如果加载他们的ClassLoader不同,那么他们是不同的类型,即他们之间不能转换,而且用instanceof操作符返回的是false。这样的话,即使用户加载了自己的java.lang.Object类,它也不是系统认为可以信赖的java.lang.Object,那么它就绕不过安全检查机制。(以上的描述只是我的猜想,我还没有看到相关的资料提到该问题,因而有待验证。)
有人说使用这种机制可以实现兼容性的升级,在软件的旧版本中使用某个旧版本的类,在升级的某些新部分中可以使用相同类的新版本,即实现内存中保留一个类的两个版本。我认为这种不应该是一种推荐的做法,在内存中保留一个类的两个版本极易在运行是引起一些莫名其妙的错误。
很可惜,我没能找到以上三种ClassLoader的源码,看不了内部的实现。在Java中,它们都是通过ClassLoader这个抽象类来表示的。以下简单的介绍一下ClassLoader内部的成员
(其中Extension ClassLoader的实现类为:sun .misc.Launcher$ExtClassLoader)
来自 http://dlevin.iteye.com/blog/772604
Java中的ClassLoader的更多相关文章
- Android解析ClassLoader(一)Java中的ClassLoader
Android解析ClassLoader(一)Java中的ClassLoader
- 一看你就懂,超详细java中的ClassLoader详解
本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载器,普通的Java开发者其实用到的不多,但对于某些框架开发者来说却非常常见.理解ClassL ...
- 【转】一看你就懂,超详细java中的ClassLoader详解
http://blog.csdn.net/briblue/article/details/54973413 ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于某些框 ...
- 一看你就懂,超详细java中的ClassLoader详解(转)
转载地址 http://blog.csdn.net/briblue/article/details/54973413 目录(?)[-] Class文件的认识 你还记得java环境变量吗 J ...
- (转)超详细java中的ClassLoader详解
转:https://blog.csdn.net/briblue/article/details/54973413 ClassLoader翻译过来就是类加载器,普通的java开发者其实用到的不多,但对于 ...
- Java中对于ClassLoader类加载器 嵌套了深度技术的价值
关于Java技术是一种不断兴起的编程语言,对于ClassLoader 是 Java 届最为神秘的技术之一,无数人被它伤透了脑筋,摸不清门道究竟在哪里.本文我带你彻底吃透 ClassLoader,让你甚 ...
- [Java类加载器]Java中classLoader浅析.
本文为在公司内部TD上写的一篇小文, 主要讲解java中classLoader基础知识, 现在拿来这里分享一下. 一.问题 请在Eclipse中新建如下类,并运行它: 1 package java.l ...
- 对java中classloader使用的一点理解(转)
先简单介绍下java的classloader,网上资料很多,就说点关键的. Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的.系统提供的类加载器主 ...
- java中的类加载器ClassLoader和类初始化
每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一 ...
随机推荐
- 基于axis2框架的两种发布webservice的方法
这次在中韩的产品定义平台的开发,有幸接触到了通过自己写webservice给其他系统调用的项目. 具体开发背景:这个平台做了几个查询接口都是,都是用servlet方式处理请求,而这边系统之间是通过we ...
- npm 介绍
安装NPM NPM的全称是Node Package Manager,如果你熟悉ruby的gem,Python的PyPL.setuptools,PHP的pear,那么你就知道NPM的作用是什么了.没 错 ...
- Leetcode: Data Stream as Disjoint Intervals && Summary of TreeMap
Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen ...
- PHP——生成随机数和日期时间
在PHP里面两个常用的函数 rand(); 生成随机数 当括号内无参数时 系统会以当前时间为种子进行随机数的生成 rand(1,10); 括号里面是生成随机数的范围,在形成的随机数在1~1 ...
- 树形DP+贪心(乱搞)(HDU4714)
题意:给出一个树形图,要求把该树形成一个环最少的步骤(断开一条边和形成一条边都需一步) 分析:很明显,要想把树形成一个环,就要先把其分裂成m条子链之后把子链形成环需要的步骤是2*m+1,所以只需要m最 ...
- extjs4.0下的日期控件的星期显示为y的解决办法
没有修改的时候的问题: 今天第一次写博客,就记录一下以前extjs4.2下运用日期组件的星期显示问题,当时找了n久,可能是extjs4.2才出来没多久,没有多少人发现这个问题或者说很少有人将Extjs ...
- 认真学习shell的第一天-数学运算
shell中的数学运算有三种方式: (1)let,用let的时候,变量名称前不用添加$ (2)[],[]中变量可使用也可不使用$ (3)(())变量名之前必须添加$
- cordova3.X 运用grunt生成plugin自定义插件骨架
Cordova提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头.麦克风等.Cordova还提供了一组统一的JavaScript类库,以及为这些 ...
- bzoj1758 [Wc2010]重建计划 & bzoj2599 [IOI2011]Race
两题都是树分治. 1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调 ...
- geotools
http://blog.tigerlihao.cn/2010/01/geotools-based-web-map-service.html