java ClassLoader 详解
2015-08-07 00:06
375 查看
1.什么是类加载器?
类加载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件。
类装在工作有ClassLoader及其子类负责,ClassLoader是一个重要的java运行时系统组件,它负责运行时查找和装入class字节码文件。
jvm运行时产生三个ClassLoader:
BootStrap ClassLoader:由C++编写,非ClassLoader子类,在java中看不到;根装载器主要负责JRE的核心类库,lib下的 rt.jar、resources.jar、charset.jar。
Ext ClassLoader:扩展类加载器,负责加载JRE扩展目录ext中的JAR类包,主要用来实现第三方的扩展功能。
App ClassLoader:负责装载ClassPath下的类包。
三个类加载器间的关系可以通过下图形象的描述:
![](https://img-blog.csdn.net/20150806085710286?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2.类的加载过程
JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize)链接又分为三个步骤,如下图所示:
![](https://img-blog.csdn.net/20150806090158909?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
1) 装载:查找和导入Class文件;
2)链接:执行验证、准备和解析步骤
a) 验证:确保Class文件被加载类的正确性;
b) 准备:为类的静态变量分配内存,并将其初始化为默认值;
c) 解析:把类中的符号引用转换为直接引用;
3)初始化:为类的静态变量赋予正确的初始值;
那为什么我要有验证这一步骤呢?首先如果由编译器生成的class文件,它肯定是符合JVM字节码格式的,但是万一有高手自己写一个class文件,让JVM加载并运行,用于恶意用途,就不妙了,因此这个class文件要先过验证这一关,不符合的话不会让它继续执行的,也是为了安全考虑吧。
准备阶段和初始化阶段看似有点矛盾,其实是不矛盾的,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后到解析(后面在说),到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10。
3. 类的初始化
注:来自 http://blog.csdn.net/gjanyanlig/article/details/6818655
类什么时候才被初始化:
1)创建类的实例,也就是new一个对象
2)访问某个类或接口的静态变量,或者对该静态变量赋值
3)调用类的静态方法
4)反射(Class.forName("com.lyj.load"))
5)初始化一个类的子类(会首先初始化子类的父类)
6)JVM启动时标明的启动类,即文件名和类名相同的那个类
只有这6中情况才会导致类的类的初始化。
类的初始化步骤:
1)如果这个类还没有被加载和链接,那先进行加载和链接
2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
3)加入类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句。
4.双亲委托机制
下图是ClassLoader的加载类流程图,以加载一个类的过程类示例说明整个ClassLoader的过程。
![](https://img-blog.csdn.net/20150807000116210?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
Java中ClassLoader的加载采用了“双亲委托机制(全盘负责委托机制)”。
双亲委托机制:某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
好处:java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都会委派给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果用户自己写了一个名为java.lang.Object的类,并放在程序的Classpath中,那系统中将会出现多个不同的Object类,java类型体系中最基础的行为也无法保证,应用程序也会变得一片混乱。双亲委托机制保证了类永远是从根装载器来装载。
java开发,都遇到过java.lang.NoSuchMethodError错误,究其原因就是有JVM的“双亲委托机制”引发的,因为在java的类路径下放了不同版本的类包,如
commons-lang2.x.jar和commons-lang3.x.jar都在类路径中,代码中使用到了common-lang3.x.jar类的某个方法,而这个方法在commons-lang2.x.jar中不存在,jvm加载时碰巧又从commons-lang2.x.jar中加载类,运行时就会抛出NoSuchMethodError错误。
类加载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件。
类装在工作有ClassLoader及其子类负责,ClassLoader是一个重要的java运行时系统组件,它负责运行时查找和装入class字节码文件。
jvm运行时产生三个ClassLoader:
BootStrap ClassLoader:由C++编写,非ClassLoader子类,在java中看不到;根装载器主要负责JRE的核心类库,lib下的 rt.jar、resources.jar、charset.jar。
Ext ClassLoader:扩展类加载器,负责加载JRE扩展目录ext中的JAR类包,主要用来实现第三方的扩展功能。
App ClassLoader:负责装载ClassPath下的类包。
三个类加载器间的关系可以通过下图形象的描述:
2.类的加载过程
JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize)链接又分为三个步骤,如下图所示:
1) 装载:查找和导入Class文件;
2)链接:执行验证、准备和解析步骤
a) 验证:确保Class文件被加载类的正确性;
b) 准备:为类的静态变量分配内存,并将其初始化为默认值;
c) 解析:把类中的符号引用转换为直接引用;
3)初始化:为类的静态变量赋予正确的初始值;
那为什么我要有验证这一步骤呢?首先如果由编译器生成的class文件,它肯定是符合JVM字节码格式的,但是万一有高手自己写一个class文件,让JVM加载并运行,用于恶意用途,就不妙了,因此这个class文件要先过验证这一关,不符合的话不会让它继续执行的,也是为了安全考虑吧。
准备阶段和初始化阶段看似有点矛盾,其实是不矛盾的,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后到解析(后面在说),到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10。
3. 类的初始化
注:来自 http://blog.csdn.net/gjanyanlig/article/details/6818655
类什么时候才被初始化:
1)创建类的实例,也就是new一个对象
2)访问某个类或接口的静态变量,或者对该静态变量赋值
3)调用类的静态方法
4)反射(Class.forName("com.lyj.load"))
5)初始化一个类的子类(会首先初始化子类的父类)
6)JVM启动时标明的启动类,即文件名和类名相同的那个类
只有这6中情况才会导致类的类的初始化。
类的初始化步骤:
1)如果这个类还没有被加载和链接,那先进行加载和链接
2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
3)加入类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句。
4.双亲委托机制
下图是ClassLoader的加载类流程图,以加载一个类的过程类示例说明整个ClassLoader的过程。
Java中ClassLoader的加载采用了“双亲委托机制(全盘负责委托机制)”。
双亲委托机制:某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
好处:java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都会委派给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果用户自己写了一个名为java.lang.Object的类,并放在程序的Classpath中,那系统中将会出现多个不同的Object类,java类型体系中最基础的行为也无法保证,应用程序也会变得一片混乱。双亲委托机制保证了类永远是从根装载器来装载。
java开发,都遇到过java.lang.NoSuchMethodError错误,究其原因就是有JVM的“双亲委托机制”引发的,因为在java的类路径下放了不同版本的类包,如
commons-lang2.x.jar和commons-lang3.x.jar都在类路径中,代码中使用到了common-lang3.x.jar类的某个方法,而这个方法在commons-lang2.x.jar中不存在,jvm加载时碰巧又从commons-lang2.x.jar中加载类,运行时就会抛出NoSuchMethodError错误。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- bootstrap初试进度条
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树