JVM中加载类的整个过程
2015-07-21 14:10
260 查看
这个问题之前绝对木有考虑过。。。今天被问到了
转自:http://my.oschina.net/xianggao/blog/87735
一、JVM中类的整个生命周期如下
加载=》验证=》准备=》解析=》初始化=》使用=》卸载
1、加载
类的加载阶段,主要是获取定义此类的二进制字节流,并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,最后在Java堆中生成一个代表这个类的java.lang.Class对象作为方法区这些数据的访问入口。相对于类加载过程的其他阶段,加载阶段是开发期可控性最强的阶段。我们可以通过定制不通的类加载器,也就是ClassLoader来控制二进制字节流的获取方式。
2、验证
验证,准备和解析其实都属于连接阶段,而验证就是连接阶段的第一步。这一阶段主要是为了确保Class文件的字节流中包含的信息复合当前虚拟机的要求,并且不会危害虚拟机自身的安全。主要验证过程包括:文件格式验证,元数据验证,字节码验证以及符号引用验证。
3、准备
准备阶段正式为类变量分配内存并设置初始值。这里的初始值并不是初始化的值,而是数据类型的默认零值。这里提到的类变量是被static修饰的变量,而不是实例变量。关于准备阶段为类变量设置零值的唯一例外就是当这个类变量同时也被final修饰,那么在编译时,就会直接为这个常量赋上目标值。
4、解析
解析时虚拟机将常量池中的符号引用替换为直接引用的过程。
5、初始化
在准备阶段,变量已经赋过一次系统要求的初始值,在初始化阶段,则是根据程序员通过程序的主观计划区初始化类变量和其他资源。Java虚拟机规范规定了有4种情况必须立即对类进行初始化(加载,验证,准备必须在此之前完成)
1)当使用new关键字实例化对象时,当读取或者设置一个类的静态字段(被final修饰的除外)时,以及当调用一个类的静态方法时,如果类未初始化,则需先初始化。
2)通过反射机制对类进行调用时,如果类未初始化,则需先初始化。
3)当初始化一个类时,如果其父类未初始化,先初始化父类。
4)用户指定的执行主类(含main方法的那个类)在虚拟机启动时会先被初始化。
除了上面这4种方式,所有引用类的方式都不会触发初始化,称为被动引用。如:通过子类引用父类的静态字段,不会导致子类初始化;通过数组定义来引用类,不会触发此类的初始化;引用类的静态常量不会触发定义常量的类的初始化,因为常量在编译阶段已经被放到常量池中了。
6、总结
在上述5个过程当中,验证,准备和解析完全由Java虚拟机主导和控制。只有加载阶段和初始化阶段程序员可以进行控制。在加载阶段可以通过实现自定义的ClassLoader来加载类的二进制流,在初始化阶段程序员则可完全按照需求来为类变量赋值。
二、执行java XXX.class的过程
找到JRE——》找到jvm.dll——》启动JVM并进行初始化——》产生Bootstrap Loader——》载入ExtClassLoader——》载入AppClassLoader——》执行java XXX.class
也有百度上回答的答案:
转自:http://my.oschina.net/xianggao/blog/87735
一、JVM中类的整个生命周期如下
加载=》验证=》准备=》解析=》初始化=》使用=》卸载
1、加载
类的加载阶段,主要是获取定义此类的二进制字节流,并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,最后在Java堆中生成一个代表这个类的java.lang.Class对象作为方法区这些数据的访问入口。相对于类加载过程的其他阶段,加载阶段是开发期可控性最强的阶段。我们可以通过定制不通的类加载器,也就是ClassLoader来控制二进制字节流的获取方式。
2、验证
验证,准备和解析其实都属于连接阶段,而验证就是连接阶段的第一步。这一阶段主要是为了确保Class文件的字节流中包含的信息复合当前虚拟机的要求,并且不会危害虚拟机自身的安全。主要验证过程包括:文件格式验证,元数据验证,字节码验证以及符号引用验证。
3、准备
准备阶段正式为类变量分配内存并设置初始值。这里的初始值并不是初始化的值,而是数据类型的默认零值。这里提到的类变量是被static修饰的变量,而不是实例变量。关于准备阶段为类变量设置零值的唯一例外就是当这个类变量同时也被final修饰,那么在编译时,就会直接为这个常量赋上目标值。
4、解析
解析时虚拟机将常量池中的符号引用替换为直接引用的过程。
5、初始化
在准备阶段,变量已经赋过一次系统要求的初始值,在初始化阶段,则是根据程序员通过程序的主观计划区初始化类变量和其他资源。Java虚拟机规范规定了有4种情况必须立即对类进行初始化(加载,验证,准备必须在此之前完成)
1)当使用new关键字实例化对象时,当读取或者设置一个类的静态字段(被final修饰的除外)时,以及当调用一个类的静态方法时,如果类未初始化,则需先初始化。
2)通过反射机制对类进行调用时,如果类未初始化,则需先初始化。
3)当初始化一个类时,如果其父类未初始化,先初始化父类。
4)用户指定的执行主类(含main方法的那个类)在虚拟机启动时会先被初始化。
除了上面这4种方式,所有引用类的方式都不会触发初始化,称为被动引用。如:通过子类引用父类的静态字段,不会导致子类初始化;通过数组定义来引用类,不会触发此类的初始化;引用类的静态常量不会触发定义常量的类的初始化,因为常量在编译阶段已经被放到常量池中了。
6、总结
在上述5个过程当中,验证,准备和解析完全由Java虚拟机主导和控制。只有加载阶段和初始化阶段程序员可以进行控制。在加载阶段可以通过实现自定义的ClassLoader来加载类的二进制流,在初始化阶段程序员则可完全按照需求来为类变量赋值。
二、执行java XXX.class的过程
找到JRE——》找到jvm.dll——》启动JVM并进行初始化——》产生Bootstrap Loader——》载入ExtClassLoader——》载入AppClassLoader——》执行java XXX.class
也有百度上回答的答案:
java程序在执行过程中,类,对象以及它们成员加载、初始化的顺序如下: 1、首先加载要创建对象的类及其直接与间接父类。 2、在类被加载的同时会将静态成员进行加载,主要包括静态成员变量的初始化,静态语句块的执行,在加载时按代码的先后顺序进行。 3、需要的类加载完成后,开始创建对象,首先会加载非静态的成员,主要包括非静态成员变量的初始化,非静态语句块的执行,在加载时按代码的先后顺序进行。 4、最后执行构造器,构造器执行完毕,对象生成。
相关文章推荐
- 数据结构—栈
- hdu 5253 连接的管道(kruskal)(2015年百度之星程序设计大赛 - 初赛(2))
- 部署otter数据库远程备份与编译
- Java Timer的使用(timer.schedule定时执行)
- MySQL查看和修改表的存储引擎
- 使用python客户端访问impala
- SAS9.3完全版启动时报错逻辑库“SASHELP”及其解决方法
- [LeetCode]String to Integer (atoi)
- beacon手札
- 【Android使用Shape绘制虚线,在4.0以上的手机显示实线】解决方案
- iOS Interface builder was unable to determine the type of xxx.xib
- boost的shared_ptr循环引用
- ajax绑定
- Tomcat配置任意目录下的Web应用程序
- DAC模式登陆(解决对象名'sys.sysobjvalues'无效)
- ThinkPHP快捷函数
- GRE写作必备句型
- AFNetworking使用
- win32 hook相关模式
- UIlable 设置行间距