准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。需要强调的是,这个时候进行内存分配的仅包括类变量,即被static修饰的变量,不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在java堆中。其次,这里所说的初始值通常情况下是数据类型的零值,假设一个类变量的定义为:
public static int value = 123;
那value变量在准备阶段过后的初始值是0而不是123,因为这时候尚未开始执行任何java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器<clinit>()方法之中,所以把value赋值为123的动作将在初始化阶段才会执行。
java中所有基本数据类型的零值如下表:
数据类型 | 零值 | 数据类型 | 零值 |
int | 0 | boolean | false |
long | 0L | float | 0.0f |
short | (short)0 | double | 0.0d |
char | ‘\u0000’ | reference | null |
byte | (byte)0 |
通常情况下初始值是零值,但也会有一些特殊情况:如果类字段的字段属性表中存在ConstantValue属性,那在准备阶段变量value就会被初始化为ConstantValue属性所指定的值,假设上面类变量value的定义变为:
public static final int value = 123;
编译时javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将value赋值为123。
参考文档:《深入理解java虚拟机》周志明著