每个编写的”.java”拓展名类文件都存储着需要执行的程序逻辑,这些”.java”文件经过Java编译器编译成拓展名为”.class”的文件,”.class”文件中保存着Java代码经转换后的虚拟机指令,当需要使用某个类时,虚拟机将会加载它的”.class”文件,并创建对应的class对象,将class文件加载到虚拟机的内存,这个过程称为类加载,这里我们需要了解一下类加载的过程,如下:
-
加载:类加载过程的一个阶段:通过一个类的完全限定查找此类字节码文件,并利用字节码文件创建一个Class对象
-
验证:目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求,不会危害虚拟机自身安全。主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证。
-
准备:为类变量(即static修饰的字段变量)分配内存并且设置该类变量的初始值即0(如static int i=5;这里只将i初始化为0,至于5的值将在初始化时赋值),这里不包含用final修饰的static,因为final在编译的时候就会分配了,注意这里不会为实例变量分配初始化,类变量会分配在方法区中,而实例变量是会随着对象一起分配到Java堆中。
-
解析:主要将常量池中的符号引用替换为直接引用的过程。符号引用就是一组符号来描述目标,可以是任何字面量,而直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。有类或接口的解析,字段解析,类方法解析,接口方法解析(这里涉及到字节码变量的引用,如需更详细了解,可参考《深入Java虚拟机》)。
-
初始化:类加载最后阶段,若该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化成员变量(如前面只初始化了默认值的static变量将会在这个阶段赋值,成员变量也将被初始化)。
上述直接摘录至:https://blog.csdn.net/javazejian/article/details/73413292
下面是我的一点补充:
加载、验证、准备、初始化、卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班的开始(不是顺序执行,而是相互交叉地混合进行的,只是开始有先后,一个过程中会激活另一个过程)。而解析阶段何时开始是不确定的。
类的加载过程java虚拟机规范没有约束,但是初始化阶段何时开始被严格定义:
- 使用new实例化时、读取静态字段时(被final修饰的除外)以及调用类的静态方法时。
- 使用放射包中的方法对类反射调用时
- 初始化一个类时,发现父类没有被初始化,则会要求父类进行初始化。
- 虚拟机启动时会初始化主类。
这5中场景被称为主动引用,其他的引用不会触发初始化过程。
参考:
https://blog.csdn.net/javazejian/article/details/73413292#t9
《深入理解java虚拟机》周志明