1、Java语言的特性
Java代码经过编译器编译成Class文件(字节码)后,就需要虚拟机将其加载到内存里面执行字节码所定义的代码实现程序开发设定的功能。
Java语言中类型的加载、连接(验证、准备、解析)、初始化都是在程序运行期间内完成的与C++不同(C++在编译期就需要进行连接),这样也使得Java语言更具灵活性。
2、虚拟机类加载的过程
(1)虚拟机什么时候进行类的加载(类加载的时机)
1)遇到new、getstatic、putstatic或者invokestatic 这四条字节码指令的时候,且该类没有进行初始化则进行该类的初始化
2)使用反射机制的时候
3)初始化类的父类
4)初始化虚拟机要执行主类
5)使用动态语言特性的时候
即当对一个类进行主动引用的时候,就会进行初始化操作,而进行被动引用的时候不进行初始化操作。
被动引用有:
a.通过子类引用父类静态字段,子类不会被初始化;
b.引用类数组不会初始化该类
c.定义常量的类被调用的时候不会被初始化,因为常量的值已经在编译期的时候就已经存储在调用类的常量池里面了。
(2)类的加载过程
1)加载
加载过程主要是发生在虚拟机外由单独的类加载器对指定的二进制字节流加载到内存(方法区)的过程,也就是Class文件的存储结构转换成内存方法区内的运行时数据结构并生成一个对应Class实例对象的过程。
2)验证
二进制字节流加载到内存后,需要对当前文件信息和格式等进行验证,包括文件格式的验证、元信息的验证、字节码验证、符号引用验证。
3)准备
已经加载到内存方法区内的类信息等经过验证通过后就需要在内存上分配指定大小的内存空间和进行自动化初始化操作(将各个类型字段设置默认值)。静态变量在这个阶段进行内存分配。准备阶段为类变量分配内存空间和设置变量初始默认值,但是这个阶段不包括局部变量的初始值设置。
4)解析
将Class文件内常量池定义的符号引用转换成直接引用,完成类信息,字段、方法等在内存上的布局
5)初始化
执行类构造器<clinit>方法的过程,变量的声明初始化在这个阶段进行。
3、接口的加载
接口的加载过程有别于类的加载过程,接口也有自己的初始化过程,用于初始化接口中所定义的成员变量。
类的加载过程的中先执行父类的加载然后再执行子类的加载,也就是要确保类的父类都已经加载了,但是接口的加载不要求其父接口进行初始化,只用真正用到父类接口的时候才进行父类的初始化。