题目
先来看一个题目,以下程序的输出结果是什么
运行结果
关于类加载机制
关于JVM的类加载
《深入理解Java虚拟机》中关于类加载是这样说的:
Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程称作虚拟机的类加载机制
看图:
加载、验证、准备、初始化、卸载 这五个阶段的顺序是确定的,而解析阶段则不一定
-
加载
“加载”是整个“类加载”的第一个阶段,这个阶段虚拟机需要完成的事情是:
1.1 通过类的全限定名来获取此Class文件的二进制字节流
1.2 将这个字节流所代表的静态存储结构转换为方法区的运行时数据结构
1.3 在内存中生成一个代表此类的 java.lang.Class度相关,作为方法区数据结构的访问入口
这个加载阶段一般是通过“双亲委派模型”来实现 -
验证
“验证"是连接阶段的第一步,这个阶段的目的是确保Class文件中的信息合法 -
准备
准备阶段正式为类中的变量分配内存并设置类变量初始值的阶段
类变量,即类的静态成员属性,被static修饰的类属性,即静态成员属性
这些变量所使用的内存分配在方法区中
“准备”完成的事情:
为类变量分配内存,并设置零值,此时静态变量并没有真正的赋值(此处的零值并不都是null,每种数据类型都有零值,例如int类型的零值是0,boolean类型的零值是false)
注意:“准备”阶段是对类变量,即静态变量进行内存分配,不是实例变量,实例变量是与对象一同初始化并分配在堆中的
-
解析
把常量池中的符号引用解析为直接引用 -
初始化
“初始化”阶段是类加载过程的最后一个步骤,
在此阶段,初始化类变量和其他资源,此阶段会自动收集类变量的赋值动作和静态代码块
JVM按照类变量和静态代码块中的在文件中定义的顺序依次执行,这就解释了上面的那个题目。 -
使用
此时,JVM就将类中编写的Java代码的主导权交给应用程序了。
题目解析
关于上面的那道题目,现在再来看
- 当在main方法中执行new B()时,触发类加载机制
- 经过加载、验证之后,到达准备阶段,在此阶段,为类变量分配内存到方法区,为每一个静态变量附零值。
- 来到初始化阶段,为类变量赋值,从前往后的顺序,首先是为b1赋值,会调用构造方法,但是实例代码块会在构造方法之前执行
- 经过两个类变量赋值之后,来到静态代码块,执行静态代码块中的顺序